@Transactional
트랜잭션(Transacntion)이란?
개념
DBMS(데이터베이스 관리 시스템) 또는 유사한 시스템에서 발생하는 연산들의 상호작용 단위
유사한 시스템이란 트랜잭션의 성공과 실패가 분명하고 상호독립적이며, 일관되고 믿을 수 있는 시스템을 의미함
데이터베이스의 상태를 변경시키기 위해 수행하는 작업 단위 또는 한꺼번에 모두 수행되어야 할 일련의 연산을 의미
필요성
데이터베이스의 데이터를 수정하는 도중에 예외가 발생할 경우, DB의 데이터들은 수정되기 전의 상태로 돌아가야 하고 다시 수정 작업이 진행되어야 함
이 때문에 데이터의 일관성을 유지하면서 안정적으로 데이터를 복구하기 위해서 트랜잭션을 사용함
특징
ACID 원칙을 적용하여 데이터 일관성과 무결성을 보장함
트랜잭션 내 연산은 모두 독릭적으로 이루어지며, 그 과정 중간에 다른 연산은 할 수 없고 하나의 연산이라도 오류가 발생하면 해당 트랜잭션은 취소되고 모두 원래대로 되돌아가야 함
트랜잭션 연산(작업)
커밋: 하나의 트랜잭션이 성공적으로 끝났으며, 데이터베이스가 일관성이 있는 상태로 유지될 때 트랜잭션이 마무리되었다는 것을 트랜잭션 관리자에게 알리기 위한 연산
롤백: 트랜잭션 처리가 비정상적으로 종료된 경우, 트랜잭션을 다시 시작하거나 트랜잭션의 부분 연산 결과를 취소시킴
스프링에서 트랜잭션 처리
0. 순수 JDBCTemplete 사용
개념
Java에서 데이터베이스 트랜잭션을 시작하는 유일한 방법으로, Connection 객체의 메서드를 이용하여 트랜잭션을 생성할 수 있음
Spring의
@Transactional
도 JDBC의 기본 방식으로 동작함
동작 방식
데이터베이스를 쓰기 위해 연결 진행함(
Connection
객체 생성)setAutoCommit(false)
로 트랜잭션을 직접 관리할 수 있음비즈니스 로직 수행 뒤, commit 실행
예외가 발생했을 때 rollback 실행
문제점
트랜잭션 동기화 문제
개발자가 직접 여러 개의 작업을 하나의 트랜잭션으로 관리하려면
connection
객체를 공유하는 등 많은 작업들을 하게 됨ex) 같은 트랜잭션을 유지하기 위해서
connection
을DAO
호출할 때마다 파라미터로 넘겨주어야 함
해결:
Spring 트랜잭션 동기화
JDBC 구현 기술이 서비스 계층에 누수되는 문제
트랜잭션을 적용하기 위해 서비스 계층이 JDBC 기술에 의존되어있음(데이터 접근 기술에 의존적인 코드)
향후 JDBC에서 JPA와 같은 기술로 바뀌면 JDBC 의존성 코드 때문에 서비스 코드도 모두 변경해야하는 문제 발생
해결:
Spring 트랜잭션 추상화
순수 비즈니스 로직과는 다른 관심사의 일(DB 접근 관련)을 수행하고 있음
해결:
Spring 선언전 트랜잭션
트랜잭션 적용 코드 반복 문제(try, catch, finally ...)
스프링은 트랜잭션과 관련한 핵심 기술 3가지를 제공하고 있음
1. 트랜잭션 동기화
개념
트랜잭션을 시작하기 위한
Connection
객체를 특별한 저장소에 보관해두고 필요할 때 꺼내쓸 수 있도록 하는 기술
TransactionSynchronizationManager
트랜잭션 동기화 저장소로, 작업 스레드마다 독립적으로
Connection
객체를 저장하고 관리함작업 쓰레드마다
Connection
객체를 독립적으로 관리하기 때문에, 멀티쓰레드 환경에서도 충돌이 발생하지 않음DataSourceUtils
을 사용해Connection
객체를 가져와 사용함
문제점: 여전히 data 접근 기술에 의존적임
2. 트랜잭션 추상화
개념
스프링은 트랜잭션 기술의 공통점을 담은 트랜잭션 추상화 기술을 제공하고 있음
이를 이용하여 애플리케이션에 각 기술(JDBC, JPA, Hibernate 등)에 종속적인 코드를 이용하지 않고도 일관되게 트랜잭션을 처리할 수 있도록 함
기술 별로 가져오는 트랜잭션 형태만 다르고 기능은 같이 때문에 추상화가 가능함
스프링 트랜잭션 추상화의 핵심:
PlatformTransactionManager
인터페이스
PlatformTransactionManager
사용할 DB(JDBC)의
DataSource
를 생성자에 넣어 트랜잭션 추상 오브젝트를 생성하여 사용함이때 환경에 맞는
TransactionManager
클래스를 DI 받아 사용함JDBC:
transactionManager = new DataSourceTransactionManager(dataSource)
JPA:
transactionManager = new JpaTransactionManager()
getTransaction()
으로 트랜잭션을 시작함
문제점: 여전히 순수 비즈니스 로직과는 다른 관심사의 일(DB 접근)을 수행함
3. AOP를 이용한 트랜잭션 분리
소스 코드에 직접 트랜잭션 관련 로직을 넣지 않고, 비즈니스 로직에서 완전히 분리하는 방식
스프링은 트랜잭션 코드와 같은 부가 기능 코드를 비즈니스 로직 클래스 밖으로 빼내서 별도의 모듈로 만드는 AOP를 고안함
이를 적용한 트랜잭션 어노테이션이
@Transactional
임
이 어노테이션을 적용하면 핵심 비즈니스 로직만 남게 됨
@Transactional 어노테이션
개념
스프링에서 많이 사용되는 선언적 트랜잭션 방식으로, 적용된 범위가 트랜잭션이 되도록 보장해줌
선언적 트랜잭션이란 설정 파일 또는 어노테이션 방식으로 간편하게 트랜잭션에 관한 행위를 정의하는 것
getConnection()
,setAutoCommit(false)
, commit(),rollback()
등의 JDBC에서 필요한 코드를 삽입해줌
사용
Spring에서 ServiceLayer에 해당 어노테이션을 추가하여 트랜잭션 처리를 진행함
서비스 클래스 혹은 메서드 단위에 어노테이션을 추가하여 사용함
@Transactional
어노테이션을 사용하라면 설정에@EnableTransactionManagement
를 추가해야 하는데, 스프링 부트에서는 자동으로 설정되어 있음
옵션
isolation
: 트랜잭션에서 일관성 없는 데이터 허용 수준을 설정(격리수준)propagation
: 트랜잭션 동작 도중 다른 트랜잭션을 호출할 때, 어떻게 할 것인지 설정하는 옵션noRollbackFor
: 특정 예외 발생 시 rollback을 수행하지 않는 옵션rollbackFor
: 특정 예외 발생 시 rollback을 수행하는 옵션timeout
: 지정한 시간 내에 메소드 수행이 완료되지 않으면 rollback을 하는 옵션readOnly
: 트랜잭션을 읽기 전용으로 설정
isolation
각 벤더별 Default 격리 수준
ORACLE : READ COMMITED
MySQL : REPEATABLE READ
SQL Server : READ COMMITED
PostgreSQL : READ COMMITED
➕ 읽기에 @Transactional(readonly=true)
를 붙이는 이유
@Transactional(readonly=true)
를 붙이는 이유JPA의 경우, 해당 옵션을
true
로 설정하면 트랜잭션이 커밋되어도 영속성 컨텍스트를 플러시 하지 않음.플러시할 때 수행되는 엔티티는 변경 감지를 위한 스냅샵 비교 로직이 수행되지 않으므로 성능을 약간 향상 시킬 수 있음
동작 원리
트랜잭션은 스프링이 지원하는 어노테이션 기반 AOP를 통해 구현되어 있음
import org.springframework.transaction.annotation.Transactional
클래스나 메소드에 @Transactional이 선언되면 해당 클래스에 트랜잭션이 적용된 프록시 객체가 생성됨
프록시 객체는 @Transactional이 포함된 메서드가 호출될 경우, 트랜잭션을 시작하고 Commit 또는 Rollback을 수행함
CheckedException
or 예외가 없을 때Commit
수행UncheckedException
이 발생하면Rollback
수행
테스트 환경에서 @Transactional 동작
반복 가능한 테스트 지원
각각의 테스트를 실행할 때마다 트랜잭션을 시작하고 테스트가 끝나면 트랜잭션을 강제로 롤백함
해당 어노테이션이 테스트 케이스에서 사용될 때만 롤백됨
Last updated