본문 바로가기

카테고리 없음

Spring Transaction, @Transactional

@Transactional Annotation을 이용한 트랜잭션 설정의 예

프로젝트 설정법은 바로 앞의 페이지를 참고하세요.


src/applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:aop="http://www.springframework.org/schema/aop"
 xmlns:p="http://www.springframework.org/schema/p"
 xmlns:tx="http://www.springframework.org/schema/tx"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
  http://www.springframework.org/schema/aop
  http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
  http://www.springframework.org/schema/tx
  http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

<bean name="dataSource"
    class="org.apache.commons.dbcp.BasicDataSource"
    p:driverClassName="oracle.jdbc.OracleDriver"
    p:url="jdbc:oracle:thin:@micropilot.co.kr:1521:ORCL"
    p:username="scott"
    p:password="tiger" />
   
 <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
     <property name="dataSource" ref="dataSource"/>
 </bean>
<!--
  <tx:advice id="txAdvice" transaction-manager="txManager">
    <tx:attributes>
      <tx:method name="get*" read-only="true" rollback-for="Exception"/>
      <tx:method name="*"/>
    </tx:attributes>
  </tx:advice>
 
  <aop:config>
    <aop:pointcut id="mybeanGetMethod" expression="execution(* test.MyBean.*(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="mybeanGetMethod"/>
  </aop:config>
 -->

 
  <tx:annotation-driven transaction-manager="txManager"/>
 
<!-- 데이터베이스 작업이 필요할 때 이 객체를 사용하면 된다(jdbcTemplate를 포함하고 있고, dataSource를 사용함)-->
 <bean id="dao"
     class="test.JdbcTemplateEmpDao"
     p:dataSource-ref="dataSource" />
 
 <bean name="myBean" class="test.MyBean">
   <constructor-arg>
    <ref bean="dao"/>
   </constructor-arg>
 </bean>

</beans>



tes/Dao.java

package test;

import java.util.List;

public interface Dao {
 public List<Emp> searchByDeptno(int deptno);
 public List<Emp> searchByEmpno(int empno);
 public boolean creditTransfer(int from, int to);
}




test/JdbcTemplateEmpDao.java

package test;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.transaction.annotation.Transactional;

/*JdbcDaoSupport클래스는 간결한 데이터베이스 소스를 지원하기 위해 JdbcTemplate 클래스를 지원하고 있다. JdbcTemplate클래스는 JDBC작업을 할 때 정형화된 코드를 내장하고 있기 때문에 반드시 필요한 것들만 전달해 주면 데이터베이스에 연결, PrepatedStatement객체생성, SQL실행등을 담당해 준다.
* JdbcTemplate객체를 사용하기 위해서는 getJdbcTemplate()를 호출하면 된다
* dataSource속성을 가지고 있기 때문에 이 클래스를 설정파일에 등록할 때는 dataSource속성에 dataSource태그의 참조를 입력해 주면 된다. 즉, JdbcDaoSupport 클래스는 JdbcTemplate객체와 dataSourc객체를 모두 사용할 수 있는 객체가 된다.
*/

public class JdbcTemplateEmpDao extends JdbcDaoSupport implements Dao{

 public List<Emp> searchByDeptno(int deptno){
 
  String sql ="select * from emp where deptno=?";
  List<Emp> list = this.getJdbcTemplate().query(sql, new Object[]{deptno}, new RowMapper(){

   @Override  /* 컬럼과 객체의 속성을 연결하는 규칙을 지정함 */
   public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
    Emp emp = new Emp(rs.getInt("EMPNO"), rs.getString("ENAME"), rs.getString("JOB"), rs.getInt("DEPTNO"));
    return emp;
   }
  });
  return list;
 }
 
 public List<Emp> searchByEmpno(int empno){
  System.out.println("Dao.searchByEmpno()");
  String sql ="select * from emp where empno=?";
  List<Emp> list = this.getJdbcTemplate().query(sql, new Object[]{empno}, new RowMapper(){

   @Override  /* 컬럼과 객체의 속성을 연결하는 규칙을 지정함 */
   public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
    Emp emp = new Emp(rs.getInt("EMPNO"), rs.getString("ENAME"), rs.getString("JOB"), rs.getInt("DEPTNO"));
    return emp;
   }
  });
  return list;
 }

 /*사번이 from인 사람이 to 에게 500을 계좌이체하는 경우를 예로  들어 2개의 SQL문장이 실행될 필요가 있는 경우 */
 /*2개 이상의 SQL문장을 연속으로 실행하던 중에 오류가 발생한 경우(RuntimeException)에는 Spring은 트랜잭션처리를
  * 실행한다. 만약 발생한 오류가 RuntimeException, Errors 이 아니라면 롤백이 실행되지 않는다.
  * RuntimeException이외의 오류발생시에도 롤백이 실행되기를 바란다면, 설정파일에 명시해 주어야 한다.
  * 예)<tx:method name="get*" read-only="true" rollback-for="Exception"/>
  */

 @Transactional
 public boolean creditTransfer(int from, int to){
  String sql_1 = "update EMPLOYEE set sal=sal-500 where empno=?";
  String sql_2 = "update EMPLOYEE set sal=sal+500 where empno=?";
 
  boolean error = true;
  this.getJdbcTemplate().update(sql_1, new Object[]{from});
 
  if(error){  throw new RuntimeException("계좌이체시 오류발생, 롤백요구되는 상황");  }
 
  this.getJdbcTemplate().update(sql_2, new Object[]{to});
  return true;
 }
}



test/MyBean.java

package test;
import java.util.*;

public class MyBean {

 private Dao dao;
 
 public MyBean(){}
 
 public MyBean(Dao dao){
  this.dao = dao;
 }
 
 public void getEname(int empno){
  List<Emp> list = dao.searchByEmpno(empno);
  System.out.println(list.get(0).getEname());
 }
 
 public boolean creditTransfer(int from, int to){
 return dao.creditTransfer(from, to);
 }
}



Main.java

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

import test.*;

public class Main {
 
 public static void main(String[] args){

   ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
   MyBean bean = (MyBean) context.getBean("myBean");
   //bean.getEname(7369);
  
   boolean success = bean.creditTransfer(7369, 7499);
   if(success){ System.out.println("계좌이체 성공"); }
   else { System.out.println("계좌이체 실패!!!!!"); }
  }
}