트랜잭션(Transaction)
- 하나의 트랜잭션은 하나의 작업단위로 처리
- 예로 추가와 삭제라는 작업이 하나의 작업으로 묶여있다면 두 작업은 모두 성공하거나 실패되어야 한다는 것이다.
- 작업이 정상적으로 종료 되었다면 영구적으로 저장(Commit) 되어야 하고 잘못되었다면 되돌려야 한다(Rollback)
- Java jdbc를 사용할 때는 커넥션 객체의 setAutoCommit(false) 메소드를 통해 오토 커밋을 해제하고 직접 커밋과 롤백을 수행할 수 있다
- Spring jdbc 나 MyBatis에서는 커넥션을 자동 생성/커밋이 되기 때문에 커밋/롤백이 자유롭지 않다. 따라서 스프링에서 트랜잭션을 관리해주는 기능 구현이 필요하다.
- jdbc를 이용해 DB 연동을 했을 때 트랜잭션 관리는 DataSourceTransactionManager 클래스를 사용한다.
- DataSourceTransactionManager 클래스는 Connection의 트랜잭션 API를 이용해서 트랜잭션을 관리해주는 트랜잭션 매니저다.
선언적 트랜잭션
1. @Transactional 어노테이션을 사용한 트랜잭션 관리
2. AOP 기반 트랜잭션 관리
- Oralcle을 사용하다면 상관없지만 MariaDB(MySQL 포함)를 사용하는 경우 ㅣnnoDB 엔진 사용해야 트랜잭션 기능을 사용할수 있다.
- InnoDB 엔진은 MySQL 5.5 이후 기본적으로 사용되었다고 한다. 만약 엔진이 MylSAM이면 lnnoDB로 변환하는 작업이 필요하다.
1. @Transactional 어노테이션을 사용한 트랜잭션 관리
1) Namespace 등록
- root-context.xml 에서 beans xmlns에 tx 항목을 추가하고 schemaLocation을 등록한다.
xmlns:tx="http://www.springframework.org/schema/tx"
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd"
2) transactionManagerBean 생성
- DataSourceTransactionManager 클래스를 Bean으로 등록하고 DriverManagerDataSource 클래스를 통해 생성된 Bean객체를 의존 주입 시킨다.
- 테스트 과정에서 스프링 jdbc 모듈에 있는 DriverManagerDataSource 클래스를 이용했지만 각자 환경에 맞는 DataSource를 의존 주입하면 된다.
- 즉, 트랜잭션을 적용할 DAO가 사용하는 DataSource 말한다.
- annotation-driven을 등록하지 않으면 @Transeactional 어노테이션을 인식하지 못한다.
<!-- 트랜잭션 관리자의 빈을 정의 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 애너테이션 기반의 트랜잭션 제어를 활성화함
aop(Aspect Oritented Programming : 관점 지향 프로그래밍)
로(그), 보(안), 트(랜잭션), 에(러) => 스프링에서 알아서 함
-->
<tx:annotation-driven/>
3) @Transactional 어노테이션을 선언한다.
- @Transactional 어노테이션은 클래스, 메소드 단위 선언 가능하다
- 클래스에 선언하게 되면 모든 메소드에 적용되고 특정 메소드에 선언시 선언된 메소드에만 적용된다. 따라서 로직흐름에 맞춰 알맞게 사용하는 것이 중용하다.
- 순위 클래스의 메소드 > 클래스 > 인터페이스의 메소드 > 인터페이스
@Transactional
public int allFileDelete (String comAttMId) {
int result = 0;
result += this.attachDao.deleteComAttachDet(comAttMId);
log.info("ck1>>>",result);
result += this.attachDao.deleteComAttachFile(comAttMId);
log.info("ck2>>>",result);
return result;
}
2. AOP 기반 트랜잭션 관리
- @Transactional 어노테이션은 필요한 메소드 또는 클래스에 선언을 해서 사용했었다. 그렇다보니 매번 선언을 해야하는 불편함이 생긴다. AOP 기반의 트랜잭션 관리는 이러한 불편함을 덜어준다.
https://lavender1122.tistory.com/347
1) Namespace 등록
- root-context.xml 에서 beans xmlns에 aop 항목을 추가하고 schemaLocation을 등록한다.
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
2) 트랜잭션 AOP 설정
- 트랜잭션을 위한 태그는 "tx" 라는 네임스페이스를 갖는다.
- 트랜잭션에 사용될 Advisor 생성한다. <tx:advise> 태그를 이용해서 특정 메소드에 어떻게 적용되는지에 대한 정책을 정할 수 이따.
- ID는 Advisor의 고유 ID이며, transaction-manager에는 트랜잭션 관리 관체를 지정한다.
- 트랜잭션 관리 객체는 위에서 Bean 객체로 생성된 DataSourceTransactionManager 클래스이다.
<tx:advice id="transactionAdvice" transaction-manager="transactionManager">
- <tx:attributes /> : 태그의 자식 태그를 선언해 트랜잭션을 관리할 메소드 및 속성을 지정할 수 있다.
- <tx:method />
- name : 트랜잭션이 적용될 메서드명 명시 .* 입력시 모든 메소드 적용
- rollback-for : 트랜잭션을 롤백할 예외 타입 명시
<tx:attributes>
<tx:method name="*" rollback-for="Exception" />
</tx:attributes>
- Advisor가 준비되면 트랜잭션이 필요한 지점에서 실행될 수 있도록 설정한다.
- 이 때 AspectJ의 pointcut 표현식을 이용한다.
<aop:config>
<!--
execution(* com.study.transaction.service.impl.*Impl.*(..))
[리턴타입 선언] - * : 모든 리턴 타입 포함
[패키지경로 선언] - com.study.transaction.service.impl : 패키지 경로
[클래스명 선언] - *Impl : 패키지내에 Impl로 끝나는 모든 클래스
[메소드명(매개변수) 선언] - *(..) : 모든 메소드 선택
-->
<aop:pointcut id="requiredTx" expression="execution(* com.study.transaction.service.impl.*Impl.*(..))"/>
<!-- 정의된 pointcut과 transactionAdvice를 연결 -->
<aop:advisor advice-ref="transactionAdvice" pointcut-ref="requiredTx" />
</aop:config>
3) @Transactional 어노테이션 없이코드 구현
package com.study.transaction.service.impl;
import javax.inject.Inject;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.study.transaction.dao.TransactionDAO;
import com.study.transaction.service.TransactionService;
import com.study.transaction.vo.TransactionVO;
@Service("transaction.TransactionService")
public class TransactionServiceImpl implements TransactionService {
@Inject
TransactionDAO transactionDAO;
@Override
public void insertEx01(TransactionVO transactionVO) throws Exception {
transactionDAO.insertData(transactionVO); // Success
transactionDAO.insertNull(); // Error! Roll back
}
출처
https://shxrecord.tistory.com/213
'이론 > 스프링' 카테고리의 다른 글
[Spring] AOP (1) | 2024.10.07 |
---|---|
[Spring] 의존성 주입(DI) 3가지 방법 (0) | 2024.09.21 |
[Spring]IoC 컨테이너(Inversion of Control) (0) | 2024.09.21 |
[Spring]스프링 MVC의 흐름 (0) | 2024.04.23 |