본문 바로가기
Spring

Spring - 트랜잭션 처리

by Big Sun 2022. 7. 21.
728x90

트랜잭션

 

먼저, spring에서 트랜잭션을 어떻게 처리하는 지에대해 알아보기 전에, 트랜잭션이 무엇인 지 알아보도록 하겠습니다.

 

트랜잭션이란?

트랜잭션 : 데이터베이스의 상태를 변화시키기 위해 수행하는 작업의 단위

  • 작업의 단위는 질의어 한 문장이 아니고, 사람이 정하는 기준에 따라 달라진다.
  • 즉, 사람이 정하는 기준에 따라 정해진다.

 

 

트랜잭션(Transaction)의 필요성

데이터베이스를 수정되는 도중에 예외가 발생된다면 DB의 데이터들은 수정되기 전 상태로 다시 되돌아가야한다.

그리고 다시 수정 작업이 진행 되어야 할 것이다.

이렇듯 여러 작업을 진행하다가 문제가 생겼을 경우 이전 상태로 롤백하기 위해 사용되는 것이 트랜잭션이다.

 

예를 들어, 게시판에 사용자가 글을 올리려고 할 때, 사용자는 글을 작성하는 페이지에 들어가서, 글을 쓴 후, 다시 게시글 목록이 보이는 페이지로 돌아가야한다.

insert,select를 하나의 작업단위로 처리하면, 데이터를 다루는 데 많은 이점이 있다.

 

트랜잭션의 성질

 

  • 원자성 : 트랜잭션이 데이터베이스에 모두 반영이 되던가, 아니면 전혀 반영이 되지 않아야한다.

일처리는 작업단위 별로 이루어져야 개발자가 다루는 데 어려움이 없다.

 

  • 일관성 : 트랜잭션은 일관성 있는 데이터베이스 상태를 유지한다.

트랜잭션이 진행되는 동안에 데이터베이스가 변경 되더라도 업데이트 된 데이터베이스로 트랜잭션이 진행되는 것이 아니라, 처음에 트랜잭션을 진행 하기 위해 참조한 데이터베이스로 진행된다.

이렇게 함으로써 각 사용자는 일관성있는 데이터를 볼 수 있다.

 

  • 독립성 : 동시에 실행되는 트랜잭션들이 서로 영향을 미치지 않도록 격리해야한다.

 

  • 지속성 : 트랜잭션을 성공적으로 마치면 결과가 항상 저장되어야 한다.

 

COMMIT

변경된 데이터를 테이블에 영구적으로 반영하는 것, 트랜잭션 처리가 완전히 끝났다는 의미이다.

데이터 변경한 후, commit 누르기 전에는 변경된 데이터를 현재 사용자만 확인 가능하고, 당연히 다른 사용자는 변경 못함.

변경된 데이터를 원래 데이터로 복구 가능

 

commit 누른 후, 변경된 데이터는 모든 사용자가 확인 가능하고, 다른 사용자들이 변경된 데이터를 변경할 수 있다.

변경된 데이터는 복구 불가능

 

ROLLBACK

롤백은 데이터 변경 사항이 취소되어 데이터의 이전 상태로 복구되며, 관련된 행에 대한 잠금이 풀리고 다른 사용자들이 데이터 변경을 할 수 있게 됨을 의미한다.

 

SAVEPOINT

말그대로, 저장점을 정의하는 것인데, 롤백할 때 현 시점에서 SavePoint까지 트랜잭션의 일부만 롤백할 수 있게 한다.

 

 


스프링에서는 트랜잭션 처리를 컨테이너가 자동으로 처리하도록 설정할 수 있는 데 이를 선언적 트랜잭션이라 한다.

 

스프링의 트랜잭션 설정에는 AOP가 사용되는 데 이때 XML 기반의 AOP와 어노테이션 설정을 사용할 수 있다.

여기서는 XML 기반의 설정을 다루겠다.

 

트랜잭션을 관리하기위한 트랜잭션 관리자라는 것이 있다.

모든 트랜잭션 관리자는 PlatformTransactionManager 인터페이스를 구현한다.

 

먼저, applicationContext.xml에 트랜잭션 관리자를 등록한다.

 

<bean id = "dataSource" class = "org.apache.commons.dbcp2.BasicDataSource" destroy-method = "close">
    <property name="driverClassName" value = "${jdbc.driver}"></property>
    <property name = "url" value = "${jdbc.url}"></property>
    <property name = "username" value="${jdbc.username}"></property>
    <property name ="password" value ="${jdbc.password}"></property>
</bean>

<bean id ="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"></property>
</bean>

 

 

DataSourceTransactionManager를 <bean>으로 등록했다고 해서 자동으로 트랜잭션이 관리되는 것이 아니라 단지 객체만 생성됬을 뿐이다.

실제로 트랜잭션 관리자의 메서드를 호출하며 실질적인 트랜잭션 관리 하는 것은 어드바이스이다.

 

<tx:advice> 엘리먼트 생성

 

<bean id = "dataSource" class = "org.apache.commons.dbcp2.BasicDataSource" destroy-method = "close">
    <property name="driverClassName" value = "${jdbc.driver}"></property>
    <property name = "url" value = "${jdbc.url}"></property>
    <property name = "username" value="${jdbc.username}"></property>
    <property name ="password" value ="${jdbc.password}"></property>
</bean>

<bean id ="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"></property>
</bean>

<tx:advice id = "txAdvice" transaction-manager="txManager">
    <tx:attributes>
        <tx:method name="get*" read-only = "true"/>
        <tx:method name="*"/>
    </tx:attributes>
</tx:advice>

 

트랜잭션 관리 기능의 어드바이스는 우리가 직접 구현하지 않으며 스프링 컨테이너가 <tx:advice>설정을 참고하여 자동으로 생성한다.

즉, 트랜잭션 관리 어드바이스 객체에 클래스 이름이나 메서드 이름을 확인 할 수 없다.

 

<tx:method> 엘리먼트 속성

 

속성 의미
name 트랜잭션이 적용될 메서드 이름을 지정
read-only 읽기 전용 여부를 지정(기본 false값) , 즉 트랜잭션 관리대상에서 제외한다는 뜻
no-rollback-for 트랜잭션을 롤백하지 않을 예외 지정
rollback-for 트랜잭션을 롤백할 예외 지정

 

 

AOP 설정을 통한 트랜잭션 적용

 

여기서는 <aop:aspect> 엘리먼트를 사용하지 않고 <aop:advisor>를 사용한다.

객체의 클래스 이름이나 메서드 이름을 모르기때문이다.

 

<bean id = "dataSource" class = "org.apache.commons.dbcp2.BasicDataSource" destroy-method = "close">
    <property name="driverClassName" value = "${jdbc.driver}"></property>
    <property name = "url" value = "${jdbc.url}"></property>
    <property name = "username" value="${jdbc.username}"></property>
    <property name ="password" value ="${jdbc.password}"></property>
</bean>

<bean id ="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"></property>
</bean>

<tx:advice id = "txAdvice" transaction-manager="txManager">
    <tx:attributes>
        <tx:method name="get*" read-only = "true"/>
        <tx:method name="*"/>
    </tx:attributes>
</tx:advice>

<aop:config>
    <aop:pointcut expression="execution(* sonny.spring.web..*(..))" id="txPointcut"/>
    <aop:advisor advice-ref = "txAdvice" pointcut-ref = "txPointcut"/>
</aop:config>

위의 설정을 해석하면 클라이언트가 어떤 메서드를 호출하고, 또 메서드의 호출 과정에서 

get*()형식을 제외한 다른 메서드가 호출되면 <tx:advice>가 동작하여 참조하는 txManager의 rollback()또는 commit()메서드를 호출한다.

 

 

이상입니다.

728x90

'Spring' 카테고리의 다른 글

Spring - BeanCreationException해결 / .metadata  (0) 2022.07.26
Spring MVC 구조  (0) 2022.07.26
Spring - AOP  (0) 2022.07.19
의존성 관리 -2  (0) 2022.07.15
의존성 관리-1  (0) 2022.07.14