Transaction Required = 트랜잭션이 필수
update, delete Query 실행 시 @Transactional을 붙여주지 않았기 때문에 발생한다.
JPA를 사용할 때 update 또는 delete를 사용할 때 @Transactional 처리를 해주어야 한다.
참고-TransactionRequiredException
선언적 트랜잭션
메서드, 클래스 인터페이스 위에 추가해 사용한다.
메서드를 실행할 때 스프링이 트랜잭션을 시작해 메서드가 정상적으로 종료되면 트랜잭션을 Commit하고, 예외가 발생하면 트랜잭션을 Rollback한다.
즉, 비정상적인 종료로 인한 Rollback이 발생할 경우 트랜잭션의 일부 작업만 데이터베이스에 반영되는 것을 방지해 데이터 일관성을 유지한다.
비즈니스 로직이 트랜잭션 처리를 필요로 할 때, 트랜잭션 처리 코드와 비즈니스 로직이 공존한다면 코드 중복이 발생하고, 비즈니스 로직에 집중하기 어렵기 때문에 트랜잭션 처리와 비즈니스 로직을 분리하기 위해 사용한다.
Spring에서 AOP를 사용한다.
- AbstractPlatformTransactionManager에서 팩토리 메서드 패턴을 사용해 PlatformTransactionManager를 확장
- TransactionInterceptor를 통해 트랜잭션의 경계를 설정하고 여기에서 주입된 PlatformTransactionManager를 사용
- SpringTransactionAnnotationParser를 통해 @Transactional 관련 속성을 파싱
- AbstractAutoProxyCreator에 의해 Proxy로 생성되고, 클라이언트가 타깃에 접근할 때는 Proxy를 거쳐 TransactionInterceptor를 사용해 트랜잭션을 열고 타깃의 메서드를 호출해 Commit, Rollback을 수행한다.
즉, 기존 코드를 바꾸지 않고 AOP Proxy가 기존 코드를 가로채 앞, 뒤로 Transaction 처리를 할 수 있는 코드를 배치해 하나의 Transaction으로 처리한다.
@Transactional을 메서드나 클래스에 명시하면 AOP를 통해 Target이 상속하고 있는 인터페이스 또는 Target 객체를 상속한 Proxy 객체가 생성된다.
Proxy 객체의 메서드를 호출하면 Target 전, 후로 트랜잭션 처리를 수행한다.
propagation(트랜잭션 전파 옵션)
Required(default)
기존 트랜잭션이 없으면 생성, 있으면 참여
트랜잭션이 필수
Requires_new
항상 새로운 트랜잭션 생성
기존 트랜잭션이 있음에도 생성 > 커넥션을 추가로 사용
Support
기존 트랜잭션이 없으면 없는대로, 있으면 참여
Not_Support
트랜잭션 없이 진행
기존 트랜잭션 있을 경우 보류
Mandatory
트랜잭션이 반드시 있어야 함
기존 트랜잭션이 없으면 IlleaglTransactionStateException 예외 발생
Never
트랜잭션 사용 X
기존 트랜잭션 있으면 IlleaglTransactionStateException 예외 발생
ReadOnly
true일 경우 읽기 전용 트랜잭션이 생성
예상치 못한 엔티티의 변경, 삭제를 예방하고 성능 최적화 발생
Isolation
트랜잭션 격리 수준 지정
Default : 기본적인 격리 수준
Read_Uncommited(Level 0) : 커밋되지 않는 데이터에 대한 읽기를 허용하는 방식
Dirty Read 문제 발생
사용자 A가 데이터를 1에서 2로 변경할 때 사용자 B가 완료되지 않은 데이터를 읽음, 이때 사용자 A가 수행한 데이터가 정상 커밋되지 않아 롤백될 경우 사용자 B가 읽은 데이터는 잘못된 데이터가 됨
Read_Commited(Level 1)
커밋된 데이터에 대해 읽기를 허용
특정 사용자가 데이터를 변경하는 동안 다른 사용자가 접근 불가
Non-Repeatable Read 문제 발생
사용자 A가 1번 데이터를 조회하고 있을 때 사용자 B가 1번 데이터를 수정하고 커밋해버리면, 사용자 A가 같은 트랜잭션에서 다시 1번 데이터를 조회했을 때 수정된 데이터가 조회되어 반복하여 데이터를 읽을 수 없음
Repeatable_Read(Level 2)
동일 필드에 대해 다중으로 동일한 결과를 보장하는 방식
트랜잭션이 완료될 때까지 Select 문장이 사용되는 모든 데이터들에 대해 Shared Lock이 걸려 다른 사용자가 그 데이터에 대한 접근이 불가능해짐
Phantom Read 문제 발생
사용자 A가 특정 범위의 데이터를 2번 읽는 트랜잭션이 수행될 때, 두번째 읽기 전에 사용자 B가 수행한 트랜잭션이 데이터를 추가해버리면 첫번째 쿼리와 두번째 쿼리의 결과가 달라짐
한 트랜잭션에서 일정한 범위의 레코드를 두 번이상 읽을 때 데이터가 불일치하는 문제
Serializable(Level 3)
데이터 일관성과 동시성을 유지하기 위해 MVCC 사용하지 않음
MVCC(Multi Version concurrency Control)
다중 사용자 데이터 베이스 성능을 위한 기술
데이터를 조회할 때 Lock을 사용하지 않고 데이터의 버전을 관리해 데이터 일관성과 동시성을 높이는 기술
트랜잭션이 완료될 때까지 Select 문장이 사용하는 모든 데이터에 Shared Lock을 걸어 다른 사용자가 해당 영역에 있는 모든 데이터에 대한 수정과 입력을 불가능하게 만들어 Phantom Read 방지
Timeout
트랜잭션 수행 시간에 대한 타임아웃을 초 단위로 지정
지정 시간 내 해당 메서드 수행이 완료되지 않을 경우 rollback
RollbackFor
체크 예외 인 Exception과 그 하위 예외들은 Rollback하지 않고 Commit
언체크 예외인 RuntimeException, Error와 그 하위 예외 발생 시 Rollback
NoRollbackFor
어떤 예외가 발생했을 때 롤백하면 안되는지 지정