Spring - Spring + iBatis 연동시 iBatis Transaction 실행 안되는 문제

Published on: 2010. 12. 13. 17:56 by louis.dev

프로젝트를 진행하다 Transaction을 수행해야 하는 query가 있었습니다. 그때 저는 iBatis의 Transaction을 통해 다음과 같이 구현하였습니다.
(Spring에서 제공하는 SqlMapClientTemplate를 이용하여 iBatis를 사용했습니다)

SqlMapClient sqlClient = template.getSqlMapClient();
try {
	sqlClient.startTransaction();
	template.insert("turotial.dataInsert", data);
	template.insert("tutorial.updateInfo", data);
	sqlClient.commitTransaction();
	return true;
} catch (SQLException e) {
	e.printStackTrace();
	return false;
} finally {
	sqlClient.endTransaction();
}


위와 같이 insert하고 update부분을 iBatis의 transaction으로 묶으려고 하였습니다.

하지만 우연치 않게 iBatis의 Transaction이 먹히지 않는것을 발견하였습니다. 왜이럴까 고민하다가 Spring에서 제공하는 Transaction을 통해 구현해 보기로 하였고, 결국 Transaction이 제대로 동작하는것을 확인 할 수 있었습니다.

저같은 경우는 Spring project를 할때 db연동에 관련한 모든 bean들을 applicationContext-iBatis.xml에 몰아 둡니다.( 관리하기가 더 편하더라구요.. 개인적 생각입니다.^^)

저는 이 ibatis.xml 에 ibatis를 통해 DB에 접근할 dataSource bean을 설정해 두었습니다.

1. transactionManager와 transactionTemplate을 bean으로 등록합니다.
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
	<property name="jndiName" value="java:comp/env/jdbc/tutorial"/>
</bean>
	
<bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
	<property name="configLocation" "classpath:sqlMapConfig.xml" />
	<property name="dataSource" ref="dataSource" />
</bean>
	
<bean id="template"
          class="org.springframework.orm.ibatis.SqlMapClientTemplate"
          p:sqlMapClient-ref="sqlMapClient"/>
    
<bean id="transactionManager" "org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="dataSource"/>
    
<bean id="transactionTemplate"  
      class="org.springframework.transaction.support.TransactionTemplate"
      p:transactionManager-ref="transactionManager"/>


위와 같이 transactionManager와 transactionTemplate bean을 dataSource를 통해 생성합니다.

2. transactionTemplate를 사용할 bean에 property로 설정합니다.
<bean id="tutorialDAO" class="tutorial.TutorialDAOImpl">
	<property name="template" ref="template"/>
	<property name="transactionTemplate" ref="transactionTemplate"/>
 </bean>


3. 해당 DAOImpl 클래스에서 field로 transactionTemplate와 setter method를 구현하여 DI가 되도록 작업해 줍니다.

4. 다음과 같이 transactionTemplate를 통해 transaction을 구현합니다.
public boolean transactionTest(final TutirialVO vo ) throws SQLException{
	boolean result = false;
	result = (Boolean)transactionTemplate.execute( new TransactionCallback() {
		public Object doInTransaction(TransactionStatus status) {
			try {
				template.insert("Tutorial.insertData", vo);
				template.insert("Tutorial.updateData", vo);
				return true;
			}catch (Exception e){
				e.printStackTrace();
				status.setRollbackOnly();
				return false;
			}
		}
	});
	return result;
}

위와 같이 transactionTemplate.execute를 실행하고 전달인자로 TransactionCallBack 인스턴스를 전달하는데, 일반적으로 TransactionCallback이 인터페이스 이기 때문에 new로 객체를 생성하고 doInTransaction method를 구현합니다.