@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("계좌이체 실패!!!!!"); }
}
}