[스프링3트랜잭션강좌/예제]@Transactional 어노테이션을 이용한 spring
framework트랜잭션(Annotation설정방식), Spring @Transactional, 스프링
교육
:namespace
prefix = o ns = "urn:schemas-microsoft-com:office:office" />
[예제를 통해 이해하자.]
1. Spring Maven Project 생성
(springtr2 라는 이름으로)
전체 이클립스 프로젝트 구성은 다음과 같다.
:namespace
prefix = v ns = "urn:schemas-microsoft-com:vml" />
<그림, 스프링 선언적트랜잭션예제
이클립스화면>
[pom.xml]
<project
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.samples</groupId>
<artifactId>springtr1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<!-- Generic properties -->
<java.version>1.6</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- Spring -->
<spring-framework.version>3.2.3.RELEASE</spring-framework.version>
<!-- Logging -->
<logback.version>1.0.13</logback.version>
<slf4j.version>1.7.5</slf4j.version>
<!-- Test -->
<junit.version>4.11</junit.version>
</properties>
<dependencies>
<!-- Spring and Transactions -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<!-- Logging with SLF4J & LogBack -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
<scope>runtime</scope>
</dependency>
<!-- Test Artifacts -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.5.4</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>3.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.1.0.7.0</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>oracle</id>
<name>ORACLE JDBC
Repository</name>
<url>http://maven.jahia.org/maven2</url>
</repository>
</repositories>
</project>
2. Emp.java
package
onj.edu.tr1.model;
public class Emp {
int empno;
String ename;
int deptno;
public Emp(int empno, String ename, int deptno) {
this.empno = empno;
this.ename = ename;
this.deptno = deptno;
}
public int getEmpno() {
return empno;
}
public void setEmpno(int empno) {
this.empno = empno;
}
public String getEname()
{
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public int getDeptno() {
return deptno;
}
public void setDeptno(int deptno) {
this.deptno = deptno;
}
}
3. OnjDao.java
package onj.edu.tr1.dao;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import javax.sql.DataSource;
import onj.edu.tr1.model.Emp;
import
org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.jdbc.core.JdbcTemplate;
import
org.springframework.jdbc.core.RowMapper;
import
org.springframework.stereotype.Repository;
import
org.springframework.transaction.annotation.Transactional;
//JdbcDaoSupport클래스는 간단한
DataSource를 지원하기 위해 JdbcTemplate
클래스를 지원.
//jdbcTemplate은
DB연결,
PrepatedStatement객체생성,
파라미터주입,
SQL문장실행,
//DB접속종료등을 전담하며
getJdbcTemplate()을 통해 얻는다.
@Repository("onjDao")
public class OnjDao{
private JdbcTemplate
jdbaTemplate;
@Autowired
public void setDataSource(DataSource
dataSource){
this.jdbaTemplate = new
JdbcTemplate(dataSource);
}
public List<Emp> getEmpByDeptno(int deptno)
{
String sql = "select empno, ename, deptno from
emp where deptno = ?";
List<Emp> list =
jdbaTemplate.query(
sql,
new Object[] { deptno
},
new RowMapper()
{
public Object
mapRow(ResultSet rs, int index) throws SQLException
{
int empno =
rs.getInt("empno");
String ename =
rs.getString("ename");
int deptno =
rs.getInt("deptno");
return
new Emp(empno, ename, deptno);
}
}
);
return list;
}
@Transactional
public void insertEmps() throws Exception
{
String sql = "insert into emp(empno, ename,
deptno) values (?, ?, ?)";
jdbaTemplate.update(sql, new Object[] { 1771, "오자바1" ,
10});
jdbaTemplate.update(sql, new Object[] { 1772, "오자바2", 10
});
jdbaTemplate.update(sql, new Object[] { 1773, "오자바3", 10
});
//같은 데이터를 넣으면 키값이 중복되어
DataAccessException 발생(런타임예외)
jdbaTemplate.update(sql, new Object[] { 1773, "오자바3", 10
});
//아래 주석을 풀면
Exception이 발생하므로 트랜잭션은 롤백
//onjoraclejava.xml에서
rollback-for="Exception"으로 정의했기 때문
//만약 정의하지 않았다면 주석을 풀더라도 트랜잭션은 롤백안됨
//throw new Exception();
}
}
4. OnjService.java
package onj.edu.tr1.service;
import java.util.List;
import onj.edu.tr1.dao.OnjDao;
import onj.edu.tr1.model.Emp;
import
org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.stereotype.Service;
@Service("onjService")
public class OnjService {
@Autowired
private OnjDao dao;
public OnjService()
{}
public OnjService(OnjDao onjDao)
{
this.dao =
onjDao;
}
public List<Emp> getEmpByDeptno(int deptno)
{
return
dao.getEmpByDeptno(deptno);
}
public void insertEmps() throws
Exception{
dao.insertEmps();
}
}
5. onjoraclejava.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:context="http://www.springframework.org/schema/context"
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-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<!-- 접속할 DB의
DataSource정의
-->
<bean name="dataSource"
class="org.apache.commons.dbcp.BasicDataSource"
p:driverClassName ="oracle.jdbc.driver.OracleDriver"
p:url = "jdbc:oracle:thin:@192.168.0.7:1521:onj"
p:username =
"scott"
p:password =
"tiger" />
<!-- 트랜잭션매니저 정의
-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property
name="dataSource" ref="dataSource"/>
</bean>
<!-- 트랜잭션 매니저 이름이
transactionManager인 경우
transaction-manager 속성 생략가능
-->
<tx:annotation-driven transaction-manager="transactionManager"/>
<context:component-scan base-package="onj.edu.tr1.dao"/>
<context:component-scan base-package="onj.edu.tr1.service"/>
<context:component-scan base-package="onj.edu.tr1.service"/>
</beans>
6. 테스트를 위한 client
program
package
onj.edu.tr1.client;
import
java.util.List;
import
onj.edu.tr1.model.Emp;
import
onj.edu.tr1.service.OnjService;
import
org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class OnjEmpTest
{
public static void main(String[] args) throws
Exception{
ApplicationContext ctx = new ClassPathXmlApplicationContext("onjoraclejava.xml");
OnjService onjService = (OnjService)ctx.getBean("onjService");
List<Emp> list = onjService.getEmpByDeptno(10);
display(list);
onjService.insertEmps();
list = onjService.getEmpByDeptno(10);
display(list);
}
public static void display(List<Emp> list) {
for(Object e: list) {
System.out.print(((Emp)e).getEmpno());
System.out.print(((Emp)e).getEname());
System.out.println(((Emp)e).getDeptno());
}
}
}
7. 결과…. 일부러 중복된 데이터를
입력했는데 정상적으로 롤백 되었다.
3월 02, 2014 5:51:25
오후
org.springframework.context.support.AbstractApplicationContext
prepareRefresh
정보: Refreshing
org.springframework.context.support.ClassPathXmlApplicationContext@bf7916:
startup date [Sun Mar 02 17:51:25 KST 2014]; root of context
hierarchy
3월 02, 2014 5:51:25
오후
org.springframework.beans.factory.xml.XmlBeanDefinitionReader
loadBeanDefinitions
정보: Loading XML bean
definitions from class path resource [onjoraclejava.xml]
3월 02, 2014 5:51:25
오후
org.springframework.beans.factory.support.DefaultListableBeanFactory
preInstantiateSingletons
정보: Pre-instantiating
singletons in
org.springframework.beans.factory.support.DefaultListableBeanFactory@15cd7a9:
defining beans
[dataSource,transactionManager,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor,onjDao,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,onjService,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor];
root of factory hierarchy
7782CLARK10
7839KING10
7934MILLER10
7771Onj110
7772Onj210
7773Onj310
------------------------
3월 02, 2014 5:51:26
오후
org.springframework.beans.factory.xml.XmlBeanDefinitionReader
loadBeanDefinitions
정보: Loading XML bean
definitions from class path resource
[org/springframework/jdbc/support/sql-error-codes.xml]
3월 02, 2014 5:51:26
오후
org.springframework.jdbc.support.SQLErrorCodesFactory <init>
정보: SQLErrorCodes
loaded: [DB2, Derby, H2, HSQL, Informix, MS-SQL, MySQL, Oracle, PostgreSQL,
Sybase]
Exception in thread
"main" org.springframework.dao.DuplicateKeyException:
PreparedStatementCallback; SQL [insert into emp(empno, ename, deptno) values (?,
?, ?)]; ORA-00001: 무결성 제약 조건(SCOTT.PK_EMP)에 위배됩니다
; nested exception is
java.sql.SQLIntegrityConstraintViolationException: ORA-00001:
무결성 제약 조건(SCOTT.PK_EMP)에 위배됩니다
at
org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:245)
at
org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72)
at
org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:605)
at
org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:818)
at
org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:874)
at
org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:882)
at
onj.edu.tr1.dao.OnjDao.insertEmps(OnjDao.java:59)
at
onj.edu.tr1.dao.OnjDao$$FastClassByCGLIB$$64f4b819.invoke(<generated>)
at
org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at
org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:698)
at
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
at
org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:96)
at
org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:260)
at
org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94)
at
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at
org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:631)
at
onj.edu.tr1.dao.OnjDao$$EnhancerByCGLIB$$c6f202f9.insertEmps(<generated>)
at
onj.edu.tr1.service.OnjService.insertEmps(OnjService.java:26)
at
onj.edu.tr1.client.OnjEmpTest.main(OnjEmpTest.java:21)
Caused by:
java.sql.SQLIntegrityConstraintViolationException: ORA-00001:
무결성 제약 조건(SCOTT.PK_EMP)에 위배됩니다
at
oracle.jdbc.driver.SQLStateMapping.newSQLException(SQLStateMapping.java:85)
at
oracle.jdbc.driver.DatabaseError.newSQLException(DatabaseError.java:133)
at
oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:206)
at
oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:455)
at
oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:413)
at
oracle.jdbc.driver.T4C8Oall.receive(T4C8Oall.java:1034)
at
oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:194)
at
oracle.jdbc.driver.T4CPreparedStatement.executeForRows(T4CPreparedStatement.java:953)
at
oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1222)
at
oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3387)
at
oracle.jdbc.driver.OraclePreparedStatement.executeUpdate(OraclePreparedStatement.java:3468)
at
oracle.jdbc.driver.OraclePreparedStatementWrapper.executeUpdate(OraclePreparedStatementWrapper.java:1350)
at
org.apache.commons.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:105)
at
org.apache.commons.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:105)
at
org.springframework.jdbc.core.JdbcTemplate$2.doInPreparedStatement(JdbcTemplate.java:824)
at
org.springframework.jdbc.core.JdbcTemplate$2.doInPreparedStatement(JdbcTemplate.java:818)
at
org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:589)
... 16 more
8. EMP TABLE SELECT 결과
SQL> select empno, ename, deptno from emp where
deptno=10;
EMPNO ENAME
DEPTNO
---------- ---------- ----------
7782 CLARK
10
7839 KING
10
7934 MILLER
10
7771 Onj1
10
7772 Onj2
10
7773 Onj3
10
9. 이번에는 OnjDao.java에서 중복된
데이터 입력하는 부분을 주석으로 막고 실행해보자.
[OnjDao.java]
package onj.edu.tr1.dao;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import javax.sql.DataSource;
import onj.edu.tr1.model.Emp;
import
org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.jdbc.core.JdbcTemplate;
import
org.springframework.jdbc.core.RowMapper;
import
org.springframework.stereotype.Repository;
import
org.springframework.transaction.annotation.Transactional;
//JdbcDaoSupport클래스는 간단한
DataSource를 지원하기 위해 JdbcTemplate
클래스를 지원.
//jdbcTemplate은
DB연결,
PrepatedStatement객체생성,
파라미터주입,
SQL문장실행,
//DB접속종료등을 전담하며
getJdbcTemplate()을 통해 얻는다.
@Repository("onjDao")
public class OnjDao{
private JdbcTemplate
jdbaTemplate;
@Autowired
public void setDataSource(DataSource
dataSource){
this.jdbaTemplate = new
JdbcTemplate(dataSource);
}
public List<Emp> getEmpByDeptno(int deptno)
{
String sql = "select empno, ename, deptno from
emp where deptno = ?";
List<Emp> list =
jdbaTemplate.query(
sql,
new Object[] { deptno
},
new RowMapper()
{
public Object
mapRow(ResultSet rs, int index) throws SQLException
{
int empno =
rs.getInt("empno");
String ename =
rs.getString("ename");
int deptno =
rs.getInt("deptno");
return
new Emp(empno, ename, deptno);
}
}
);
return list;
}
@Transactional
public void insertEmps() throws Exception
{
String sql = "insert into emp(empno, ename,
deptno) values (?, ?, ?)";
jdbaTemplate.update(sql, new Object[] { 1771, "오자바1" ,
10});
jdbaTemplate.update(sql, new Object[] { 1772, "오자바2", 10
});
jdbaTemplate.update(sql, new Object[] { 1773, "오자바3", 10
});
//같은 데이터를 넣으면 키값이 중복되어
DataAccessException 발생(런타임예외)
//jdbaTemplate.update(sql, new Object[] { 1773, "오자바3", 10
});
//아래 주석을 풀면
Exception이 발생하므로 트랜잭션은 롤백
//onjoraclejava.xml에서
rollback-for="Exception"으로 정의했기 때문
//만약 정의하지 않았다면 주석을 풀더라도 트랜잭션은 롤백안됨
//throw new Exception();
}
}
[cOnjEmpTest.java 실행 결과]
3월 02, 2014 5:55:36
오후
org.springframework.context.support.AbstractApplicationContext
prepareRefresh
정보: Refreshing
org.springframework.context.support.ClassPathXmlApplicationContext@a6af6e:
startup date [Sun Mar 02 17:55:36 KST 2014]; root of context
hierarchy
3월 02, 2014 5:55:36
오후
org.springframework.beans.factory.xml.XmlBeanDefinitionReader
loadBeanDefinitions
정보: Loading XML bean
definitions from class path resource [onjoraclejava.xml]
3월 02, 2014 5:55:37
오후
org.springframework.beans.factory.support.DefaultListableBeanFactory
preInstantiateSingletons
정보: Pre-instantiating
singletons in
org.springframework.beans.factory.support.DefaultListableBeanFactory@52a22d:
defining beans
[dataSource,transactionManager,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor,onjDao,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,onjService,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor];
root of factory hierarchy
7782CLARK10
7839KING10
7934MILLER10
7771Onj110
7772Onj210
7773Onj310
------------------------
7782CLARK10
7839KING10
7934MILLER10
7771Onj110
7772Onj210
7773Onj310
1771오자바110
1772오자바210
1773오자바310
[ORACLE EMP 테이블 실행결과]
SQL> select empno, ename, deptno from emp where
deptno=10;
EMPNO ENAME
DEPTNO
---------- ---------- ----------
7782 CLARK
10
7839 KING
10
7934 MILLER
10
7771 Onj1
10
7772 Onj2
10
7773 Onj3
10
1771 오자바1 10
1772 오자바2 10
1773 오자바3 10
[OnjDao.java에서 //throw new
Exception(); 부분 주석을 출고 테스트]
-
onjoraclejava.xml에서 <tx:method name="*"
propagation="REQUIRED" rollback-for="Exception"/>인
경우
트랜잭션은 롤백된다.
-
onjoraclejava.xml에서 <tx:method name="*"
propagation="REQUIRED“/>인 경우
트앤잭션은 롤백되지 않는다. 정상 commit된다.
오라클자바커뮤니티에서 운영, 개발자 전문교육, 개인80%환급 오엔제이프로그래밍실무교육센터(www.onjprogramming.co.kr)
평일주간(9:30~18:30) 개강
(3/10)[기업100%환급]Spring ,MyBatis,Hibernate실무과정
(3/10)[기업100%환급]SQL기초에서 Schema Object까지
(3/10)C#4.0,ADO.NET,Network 프로그래밍
(3/11)[채용예정자]오라클자바개발잘하는신입뽑기2개월
(3/17)[기업100%환급]자바기초에서 JDBC, Servlet/JSP까지
(3/24)[기업100%환급][기업100%환급]PL/SQL,ORACLE HINT,TUNING
평일야간(19:00~22:00) 개강
(3/11)안드로이드개발자과정
(3/11)iPhone 하이브리드 앱 개발 실무과정
(3/13)Spring3.X, MyBatis, Hibernate실무과정
(3/14)자바기초에서JSP,Ajax,jQuery,Spring3.2,MyBatis까지
(3/18)SQL초보에서실전전문가까지
(3/20)웹퍼블리싱 마스터
(3/28)C#,ASP.NET마스터
주말(10:00~18:00) 개강
(3/08)JAVA&WEB프레임워크실무과정
(3/09)C#,ASP.NET마스터
(3/15)웹퍼블리싱 마스터
(3/15)Spring3.X, MyBatis, Hibernate실무과정
(3/15)닷넷실무자를위한WPF개발자과정
(3/22)안드로이드개발자과정
(3/22)자바기초에서JSP,Ajax,jQuery,Spring3.2,MyBatis까지
(3/29)SQL초보에서실전전문가까지
주말저녁(18:30~22:20) 개강
(3/08)자바기초에서JSP,Servlet,Ajax,jQUERY,스프링,마이바티스,하이버네이트
(3/15)SQL기초에서 Schema Object까지
댓글 없음:
댓글 쓰기