2022-09-21 23:54:43
스프링을 사용하는 자바 개발자가 알아야 할 트랜잭션에 대한 간단한 개념과 주의사항에 대해 포스팅합니다.
트랜잭션의 특징에는 흔히들 알고 있는 ACID 네가지 특징이 있습니다.
개발자가 비즈니스 로직에만 집중할 수 있도록 스프링은 크게 2가지 트랜잭션 기술을 지원해줍니다.
바로 @Transactional
어노테이션을 이용한 트랜잭션 방식입니다. 선언적방식은 Spring AOP를 이용한 방식입니다.
TransactionTemplate
을 구현한 PlatformTransactionManager
구현체를 사용합니다.트랜잭션의 특징 중 하나인 격리레벨에 따라 트랜잭션 경쟁 문제는 복잡해집니다.
참고로 흔히들 사용하는 mysql의 기본 격리 레벨은 REPEATABLE READ(Level 2) 입니다.
데이터베이스의 격리레벨은 다음과 같습니다.
READ UNCOMMITED : 트랜잭션 실행 도중 커밋되지 않은 데이터를 읽을 수 있습니다.
더티 리드(Dirty Read) : 다른 트랜잭션이 아직 커밋하지 않은 데이터를 읽을 수 있습니다.
READ COMMITED : 트랜잭션 실행 도중 읽는 데이터들은 모두 커밋된 데이터들입니다.
UNREPEATABLE READ : 다른 트랜잭션에 의해 커밋된 데이터를 읽게 되어 한 트랜잭션 내에서 SELECT를 두번 했을 경우 다른 값이 나올 수 있습니다.
REPEATABLE READ : 트랜잭션 실행 후 읽는 모든 데이터는 같은 값을 보장합니다. (mysql Default level)
트랜잭션 실행동안 읽는 모든 데이터에 Shared Lock을 걸어서 읽기는 가능하지만 수정은 불가능하게 만듭니다.
팬텀 리드(PHANTOM READ) : 일정 범위의 레코드를 읽었을 때 다른 결과값이 나올 수 있습니다. (트랜잭션이 끝나지 않았는데도 원래는 없던 유령값이 존재할 수 있음.)
SERIALIZABLE LEVEL : 트랜잭션 종료시까지 모든 데이터에 락을 걸어 최고 수준의 정합성을 보장합니다.
팬텀리드 방지.
당연히 SERIALIZABLE LEVEL을 사용해야 할 것 같지만, 성능문제로 주로 READ COMMITED, REPEATABLE READ 격리레벨을 주로 사용합니다. 4번으로 갈수록 데이터 정합성은 높지만, 성능이 떨어집니다.
트랜잭션은 가능한 한 짧아야 합니다. -> Locking 시간을 짧게 가져가자.
CheckedException이 발생하는 경우에는 트랜잭션이 롤백되지 않습니다. UnchckedException은 예상치 못한 오류라 롤백시키는 것이 Default 전략입니다.(라고 우아한 형제들에서 누군가가)
동일한 클래스 내에서 @Transactional
이 붙지 않은 상위 메소드가 @Transactional
이 붙어 있는 하위 메소드를 호출할 경우 트랜잭션은 동작하지 않습니다. 1. 이 경우처럼 트랜잭션 관리가 어려운 이유는 , 트랜잭션이 동작하지 않는 오류를 프로그램 실행 전에는 알 수 없다는 점 때문입니다. 2. 스무스하게 프로그램은 실행되겠지만, 오류가 발생했을 경우 롤백이 되지 않는다던가 예기치 못한 데드락 상황을 겪게 될 수 있습니다.
테스트코드에서 @Transactional
은 무조건 Rollback 만 일어난다는 점.
@Transaction
에서 발생한 예외라고 해서 무조건 롤백은 아닙니다. 참고사이트 :
https://yeonyeon.tistory.com/223
https://goddaehee.tistory.com/167
https://joojimin.tistory.com/68