본문 바로가기

Frame Work/Spring

Spring Transaction

 

Transaction?

 

트랜잭션은 성공적으로 처리되거나 또는 하나라도 실패하면 완전히 실패를 해야 하는 경우에 사용 됩니다.

 

예를 들어 도서구매 과정을 보면 ① 결제를 수행한다. ② 결제 내역을 저장한다. ③ 구매 내역을 저장한다. 이렇게 3단계로 이루어질 것이다. 이와 같은 과정은 구매 시 반드시 성공적으로 이루어져야 한다. 한 가지 과정이라도 실패할 경우 반드시 모든 과정이 취소되어야 합니다.

 

Spring Transaction

 

스프링은 코드 기반의 트랜잭션 처리뿐만 아니라 선언적 트랜잭션을 지원하고 있습니다. 

 

개발자가 직접적으로 트랜잭션의 범위를 코드 수준에서 정의하고 싶은 경우엔 스프링이 제공하는 Transaction Template class를 이용하여 손쉽게 트랜잭션의 적용 범위를 지정할 수 있습니다.

 

스프링의 Transaction은 데이터베이스 연동 기술에 상관없이 Transaction Manager를 통한 동일한 방식으로 트랜잭션을 처리할 수 있습니다.

 

Spring Transaction Manager

- Spring은 PlatformTransactionManager 인터페이스를 이용해서 트랜잭션 처리를 추상화하였고 데이터베이스 연동 기술에 따라 알맞은 PaltformTransactionManager 구현 클래스를 제공하고 있기 때문에 각 기술에 따른 트랜잭션 처리를 수행합니다. 

 

 

 

* JDBC 기술을 이용해서 데이터베이스 연동을 처리 할 경우 

 

<!-- applicationContext.xml -->

<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close" 
 p:driverClassName="oracle.jdbc.driver.OracleDriver" p:username="mytest" p:password="mytest" />
<bean id="transactionManager" 
class="org.springframework.jdbc.datasource.DataSourceTransactionManager" 
p:dataSource-ref="dataSource"/>

 

- DataSourceTransactionManager는 dataSource 프로퍼티를 통해서 전달받은 DataSource로 부터 Connection을 가져온 뒤 Connection의 commit(), rollback()등의 메서드로 처리합니다. 

 

 

* 하이버네이트 기술을 이용해서 데이터베이스 연동을 처리할 경우 

 

<bean id="transactionManager" 
class="org.springframework.orm.hibernate3.HibernateTransactionManager" 
p:sessionFactory-ref="sessionFactory" />
<!-- 세션 팩토리 생성 -->
<bean id="sessionFactory" 
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mappingResource">
... </property>
<property name="hibernateProperties">
... </property>
</bean>

 

* JPA 기술을 이용해서 데이터 베이스 연동을 처리하는 경우 

 

<bean id="entityManagerFactory" 
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
... </bean>

<!-- JpaTransactionManager로 관리한다. -->

<bean id="transactionManager" 
class="orm.springframework.orm.jpa.JpaTransactionManager" 
p:entityManagerFactory-ref="entityManagerFactory" />

 

 

TransactionTemplate 사용한 Transaction 

 

* 상품 코드 예시 

 

public class PlaceOrderServiceImpl implements PlaceOrderService{
 ...
 @Ovarride
 public PurchaseOrderResult order(PurchaseOrderRequest orderRequest)
throws ItemNotFoundException{
Item item = itemDao.findById(orderRequest.getItemId());
if(item == null) throw new ItemNotFoundException(orderRequest.getItemId());
PaymentInfo paymentinfo = new PaymentIntfo(item.getPrice());
paymentInfoDao.insert(paymentInfo);

PurchaseOrder order = new PuchaseOrder(
item.getId(), orderRequest.getAddress(), paymentInfo.getId());
purchaseOrderDao.insert(order);
return new PurchaseOrderResult(item, paymentInfo, order);
 }
}

 

위의 코드의 진행 방식 

 

1) itemDao로부터 구매하려는 상품정보를 구한다. 상품정보가 존재하지 않을 경우 예외를 발생 시킵니다.

 

2) paymentInfoDao를 이용해서 결제정보(PaymentInfo)를 데이터베이스에 삽입합니다.

 

3) purchaseOrderDao를 이용해서 구매 주문 정보(PurchaseOrder)를 데이터베이스에 삽입합니다.

 

 

* TransactionTemplate 설정

 

<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate" 
p:transactionManager-ref="transactionManager" />
<bean id="placeOrderService" class="tommy.spring.store.PlaceOrderServiceTransactionTemplateImpl" 
p:transactionTemplate-ref="transactionTemplate" .../>

 

* setTransactionTemplate. class 적용 

 

import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;

public class PlaceOrderServiceTxTemplateImple implements PlaceOrderService{
 	private ItemDao itemDao;
 	private PaymentInfoDao paymentInfoDao;
 	private PurchaseOrderDao purchaseOrderDao;
 	private TransactionTemplate transactionTemplate;
		...
 
 public void setTransactionTemplate(TransactionTemplate transactionTemplate){
			this.transactionTemplate = transactionTemplate;
 }
 
 @Override
 public PurchaseOrderResult order(final PurchaseOrderResult orderRequest) 
													throws ItemNotFoundException{
					return transactionTemplate.execute(new TransactionCallback<PurchaseOrderResult>(){
							@Override
							public PurchaseOrderResult doInTransaction(TransactionStatus status){
									Item item = itemDao.findById(orderRequest.getItemId());
                                    if(item == null) 
                                     		throw new ItemNotFoundException(orderRequest.getItemId());
                                    PaymentInfo paymentinfo = new PaymentIntfo(item.getPrice());
                                    paymentInfoDao.insert(paymentInfo);
                                    PurchaseOrder order = new PuchaseOrder(
                                     		item.getId(), orderRequest.getAddress(), paymentInfo.getId());
                                    purchaseOrderDao.insert(order);
                                    return new PurchaseOrderResult(item, paymentInfo, order);
						}
			});
 	}
}

 

 

- TransactionTemplate.execute() 메서드는 트랜잭션을 시작한 뒤 파라미터로 전달받은 TransactionCallback 구현 객체의 doInTransaction() 메서드를 호출합니다. 

 

- doInTransaction() 메서드의 실행이 종료되면 트랜잭션을 commit 합니다. 만약 이때 예외나 에러가 발생한다면 트랜잭션을 rollback 합니다. 

 

- 일반적으로 TransactionTemplate 클래스를 사용할 때는 TransactionCallback 인터페이스의 구현 클래스를 작성하기 보다는 위의 예제처럼 익명이너클래스를 통해서 TransactionCallback 객체를 TransactionTemplate.execute() 메서드에 전달합니다. 

 

 

선언적 트랜잭션을 통한 Transaction

 

1) <tx: advice> 태그를 이용한 트랜잭션 처리 

 

- 태그는 스프링2.0부터 지원하는 확장태그이며  xml 파일에 tx 네임스페이스를 추가하면 됩니다.

 

<beans xmlns="http://www.springframework.org/schema/beans"
x m l n s : p = " h t t p : / / w w w . s p r i n g f r a m e w o r k . o r g / s c h e m a / p " 
xmlns:aop="http://www.springframework.org/schema/aop"
x m l n s : t x = " h t t p : / / w w w . s p r i n g f r a m e w o r k . o r g / s c h e m a / t x "
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans 
 http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
 http://www.springframework.org/schema/aop
 http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
 http://www.springframework.org/schema/tx
 http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
 
 
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager" 
p:dataSource-ref="dataSource" />

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

 

위와 같이 xml에 tx 태그는 Advisor만 생성하는 것이지 실제로 트랜잭션을 적용하는 것은 아니다. 실제 트랜잭션의 적용은 AOP를 통해서 이루어진다.

 

 

* AOP 설정 

 

<aop:config>
<aop:pointcut expression="execution(public * tommy.spring..*Service.*(..))" 
id="servicePublicMethod" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="servicePublicMethod" />
</aop:config>

 

* 참고사항 

 

스프링 트랜잭션은 기본적으로 RuntimeException및 Error에 대해서만 롤백 처리를 수행합니다.

따라서 Throwable이나 Exception 타입의 예외가 발생하더라도 롤백이 되지 않고 예외가 발생하기 전까지의 작업이 커밋됩니다.

 

이 때, <tx:method> 태그의 rollback-for 속성과 no-rollback-for 속성을 통한 롤백 처리가 가능합니다. 

 

rollback-for 속성은 예외 발생 시 롤백 작업을 수행할 예외타입을 설정하고 no-rollback-for 속성은 예외가 발생하더라도 롤백하지 않을 예외타입을 설정합니다. 명시할 예외타입이 한 개 이상인 경우 각각의 예외는 콤마로 구분합니다. 

 

<tx:method name="regist" rollback-for="Exception" no-rollback-for="MemberNotFoundException" />

 

2) @Transactional을 통한 트랜잭션 처리 

 

 

import org.springframework.transaction.annotation.Transactional;

... 

public class PlaceOrderServiceAnnoImpl implements PlaceOrderService{
	... 
		@Overrride
		@Transactional(propagation=Propagation.REQUIRED)
		public PurchaseOrderResult order(PurchaseOrderRequest orderRequest)
													throws ItemNotFoundException{
				... 

			}
}

 

 

@Transactional 어노테이션이 적용된 스프링 빈에 실제로 트랜잭션을 적용하려면 다음과 같이 태그를 설정하면 된다.

 

<tx:annotation-driven transaction-manager="transactionManager" />
 <bean id="placeOrderService" class="tommy.spring.store.PlaceOrderServiceAnnoImpl" .../>

 

<tx: annotation-driven>태그 대신 PersistenceAnnotationBeanPostProcessor 클래스를 빈으로 등록해도 된다.

 

<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor">

 

 

'Frame Work > Spring' 카테고리의 다른 글

MVC FrameWork 구조  (0) 2022.10.26
MVC pattern  (0) 2022.10.25
Spring JDBC  (0) 2022.10.21
Spring AOP  (0) 2022.10.20
Spring DI  (0) 2022.10.19