스프링환경에서 트랜잭션 사용하기

최고고·2025년 5월 28일
0

스프링환경에서 트랜잭션 사용하는 방법 3가지
1. AOP 방식
2. @Transactional 어노테이션
3. 객체로 commit(), rollback()

1. AOP

- 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>

2. @Transactional

- 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>

3. 객체로 접근 (직접적으로 제어하려할때)

- PlatformTransactionManager와 TransactionStatus를 사용해서 commit() 또는 rollback()을 수동으로 처리
PlatformTransactionManager: 트랜잭션 매니저 (스프링이 주입)

DefaultTransactionDefinition: 트랜잭션 속성 정의
트랜잭션 설정을 정의하는 객체 생성.//
예) 전파 방식, 격리 수준, 읽기 전용 여부 등을 설정 가능.

TransactionStatus: 트랜잭션 상태 객체

  1. 서비스구현클래스에 의존성 주입
    private PlatformTransactionManager transactionManager;
  2. 트랜잭션설정하고자하는 메서드 내부에 트랜잭션 설정객체 생성
    DefaultTransactionDefinition def = new DefaultTransactionDefinition();
  3. 전파설정 def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
    REQUIRED: 이미 트랜잭션이 존재하면 참여하고, 없으면 새로 시작함.
  4. 트랜잭션 시작 (상태 반환하는) 객체 생성 -> 상태를가지고 커밋/롤백
    TransactionStatus status = transactionManager.getTransaction(def);
  5. try 내부에 db 조작 로직 후 검증로직에 따라 RuntimeException을 던져줌
    commit 호출, catch 부에 rollback 호출
		@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()

https://innovation123.tistory.com/223

https://jjingho.tistory.com/174

0개의 댓글