Spring Transaction

This section describes how to troubleshoot the transfer example in the Spring JDBC section.

Modify applicationContext.xml like below.

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="myBank" />
  </bean>

  <bean id="myBank" class="net.java_school.bank.MyBank">
    <property name="dao" ref="myBankDao" />
  </bean>

  <bean id="myBankDao" 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>

Since we made deposit and withdrawal methods to return nothing, so we don't know whether the deposit or withdrawal was successful or not.

Modify deposit and withdrawal methods to return an integer value.

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);    
}

Set the transaction using annotations like below.

MyBank.java
package net.java_school.bank;

import java.util.List;

import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Transactional(propagation=Propagation.SUPPORTS)
public class MyBank implements Bank {
  
  //..omit..
  
  @Override
  @Transactional(propagation=Propagation.REQUIRED)
  public void transfer(String from, String to, double amount) {
    int check = dao.withdraw(from, amount);
    if (check < 1) {
      throw new RuntimeException("Withdrawal Failed!");
    }
    check = dao.deposit(to, amount);
    if (check < 1) {
      throw new RuntimeException("Deposit Failed!");
    }
  }

  //..omit..
  
}

Modify the main method of BankUi.java like below.

ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); //XML
//AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(BankConfig.class); //JavaConfig

Try to transfer some money from account 101 to account 505 that do not exist. You can see that the transaction manager cancels the transfer, leaving the balance in account 101 intact.

Remove the @Transactional(propagation = Propagation.REQUIRED) above the transfer() method in the MyBank.java and try transfer again to see the difference.

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 myBankDao() {
    MyBankDao bankDao = new MyBankDao();
    bankDao.setDataSource(dataSource());
    return bankDao;
  }

  @Bean
  public Bank myBank() {
    Bank bank = new MyBank();
    bank.setDao(myBankDao());
    return bank;
  }

  @Bean
  public BankUi bankUi() {
    BankUi ui = new BankUi();
    ui.setBank(myBank());
    ui.setStream(System.out);
    return ui;
  }
  
}

First, comment out all contents of the beans element in applicationContext.xml and modify the main method of BankUi.java as shown below.

//ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); //XML
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(BankConfig.class); //JavaConfig

Final Source: https://github.com/kimjonghoon/transaction