스프링환경에서 트랜잭션 사용하는 방법 3가지
1. AOP 방식
2. @Transactional 어노테이션
3. 객체로 commit(), rollback()
- context-transaction.xml 에 아래와 같이 정의해줌
포인트컷을 지정해줘야함 (적용시킬 클래스)
<aop:config>
<aop:pointcut id="requiredTx" expression="execution(* egovframework.example.sample..impl.*Impl.*(..)) "/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="requiredTx" />
</aop:config>
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:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" rollback-for="Exception"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="requiredTx" expression="execution(* egovframework.example.sample.impl.*Impl.*(..)) "/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="requiredTx" />
</aop:config>
</beans>
- pom.xml에 tx 의존성 주입
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>스프링버전</version>
</dependency>
- <tx:annotation-driven/>
context-transaction.xml 에 추가
- 사용할 클래스에서 어노테이션 @Transactional 적용
- xml 전문
beans 의 xsi:schemaLocation
에서 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
스프링버전 주의 의존성에 넣은 버전 맞춰야됨
<?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:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" rollback-for="Exception"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="requiredTx" expression="execution(* egovframework.example.sample..impl.*Impl.*(..)) "/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="requiredTx" />
</aop:config>
<tx:annotation-driven/>
</beans>
- PlatformTransactionManager와 TransactionStatus를 사용해서 commit() 또는 rollback()을 수동으로 처리
PlatformTransactionManager
: 트랜잭션 매니저 (스프링이 주입)
DefaultTransactionDefinition
: 트랜잭션 속성 정의
트랜잭션 설정을 정의하는 객체 생성.//
예) 전파 방식, 격리 수준, 읽기 전용 여부 등을 설정 가능.
TransactionStatus
: 트랜잭션 상태 객체
private PlatformTransactionManager transactionManager;
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = transactionManager.getTransaction(def);
@Override
public void insertBinaryFile_tran(FileVO vo, File file) throws Exception {
File succsessDir = new File(filePath + "/succsess"); //성공시 디렉토리
File failDir = new File(filePath + "/fail"); //실패시 디렉토리
// 트랜잭션 설정 객체 생성
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setName("transId");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); //전파설정 REQUIRED: 이미 트랜잭션이 존재하면 참여하고, 없으면 새로 시작함.
//트랜잭션 시작 (상태 반환) -- 상태를가지고 커밋/롤백
TransactionStatus status = transactionManager.getTransaction(def);
try {
fileMapper.insertBinaryFile(vo);
if(!succsessDir.exists()) succsessDir.mkdir();
Path originPath = Paths.get(file.getPath(),"ddfdf");
Path targetPath = Paths.get(succsessDir.getPath(),file.getName());
if(Files.move(originPath,targetPath)==null) throw new RuntimeException("파일이동 에러");
transactionManager.commit(status);
} catch (Exception e) {
e.printStackTrace();
if(!failDir.exists()) failDir.mkdir();
Files.move(Paths.get(file.getPath()), Paths.get(failDir.getPath(), vo.getFileName()));
transactionManager.rollback(status);
throw new Exception("파일 이동실패로 롤백함",e);
}
}
또는 SqlSessionFactory 사용하기
✅ SqlSessionFactory 란?
-DB 연결 설정과 sql 세션 생성
예 : SqlSession session = sqlSessionFactory.openSession()
참고:
https://hi-hahahoho.tistory.com/91#%F0%9F%94%A6_openSession()