스프링 트랜잭션
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<aop:aspectj-autoproxy />
<bean id="testLogger" class="net.java_school.commons.TestLogger" />
<bean id="bankUi" class="net.java_school.bank.BankUi">
<property name="stream" value="#{T(System).out}" />
<property name="bank" ref="bank" />
</bean>
<bean id="bank" class="net.java_school.bank.MyBank">
<property name="dao" ref="bankDao" />
</bean>
<bean id="bankDao" class="net.java_school.bank.MyBankDao">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:XE" />
<property name="username" value="scott" />
<property name="password" value="tiger" />
</bean>
</beans>
지금까지 입금과 출금 메소드는 void를 반환하도록 설계했기에 입금이나 출금이 성공 또는 실패했는지를 알 수 없었다. 입금과 출금시 dao가 정수값을 리턴하도록 자바 클래스를 수정한다.
BankDao.java
//입금 public int deposit(String accountNo, double amount); //출금 public int withdraw(String accountNo, double amount);
MyBankDao.java
@Override
public int deposit(String accountNo, double amount) {
Map<String, Object> params = new HashMap<String, Object>();
params.put("amount", amount);
params.put("accountNo", accountNo);
return getNamedParameterJdbcTemplate().update(DEPOSIT, params);
}
@Override
public int withdraw(String accountNo, double amount) {
Map<String, Object> params = new HashMap<String, Object>();
params.put("amount", amount);
params.put("accountNo", accountNo);
return getNamedParameterJdbcTemplate().update(WITHDRAW, params);
}
다음과 같이 어노테이션을 사용해 트랜잭션을 설정한다.
MyBank.java
package net.java_school.bank;
import java.util.List;
import org.springframework.transaction.annotation.Transactional;
public class MyBank implements Bank {
//..중간 생략..
@Override
@Transactional
public void transfer(String from, String to, double amount) {
try {
int check = dao.withdraw(from, amount);
if (check < 1) throw new RuntimeException("출금 실패");
check = dao.deposit(to, amount);
if (check < 1) throw new RuntimeException("입금 실패");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
//..중간 생략..
}
테스트하기 전에 BankUi.java의 메인 메소드를 아래를 참조해 수정한다.
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); //XML
//AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(BankConfig.class); //JavaConfig
컴파일하고 실행한 후, 101 계좌에서 505 계좌(존재하는 않는 계좌)로 이체를 시도한다. 테스트에 성공했다면(즉, 이체가 취소되었다면), MyBank 클래스에서 transfer() 메소드 위에 있는 @Transactional을 제거하고 다시 이체를 시도한다.
JavaConfig 설정
BankConfig.java
package net.java_school.bank;
import javax.sql.DataSource;
import net.java_school.commons.TestLogger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@EnableAspectJAutoProxy
@EnableTransactionManagement
public class BankConfig {
@Bean
public TestLogger testLogger() {
return new TestLogger();
}
@Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("oracle.jdbc.driver.OracleDriver");
dataSource.setUrl("jdbc:oracle:thin:@127.0.0.1:1521:XE");
dataSource.setUsername("scott");
dataSource.setPassword("tiger");
return dataSource;
}
@Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
@Bean
public BankDao bankDao() {
MyBankDao bankDao = new MyBankDao();
bankDao.setDataSource(dataSource());
return bankDao;
}
@Bean
public Bank bank() {
Bank bank = new MyBank();
bank.setDao(bankDao());
return bank;
}
@Bean
public BankUi bankUi() {
BankUi ui = new BankUi();
ui.setBank(bank());
ui.setStream(System.out);
return ui;
}
}
테스트하기 전에, applicationContext.xml 설정을 모두 주석 처리한다. BankUi.java의 메인 메소드를 아래를 참조해 수정한다.
//ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); //XML
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(BankConfig.class); //JavaConfig
