Spring AOP를 기반으로 트랜잭션을 처리하는 선언적 트랜잭션 어노테이션
Transaction 정의
데이터베이스의 데이터/상태를 조작하는 작업 단위
한 번에 수행되어야 하는 연산들
ACID 원칙
원자성 Atomicity
한 트랜잭션 내에서 실행한 작업들은 한 번에 처리한다.
모두 성공하거나 모두 실패한다. 부분적으로 성공하는 일이 없도록 보장한다.
일관성 Consistency
일관성 있는 데이터베이스 상태를 보장한다
격리성 Isolation
동시에 실행되는 트랜잭션들이 서로 영향을 미치지 않게 격리한다.
영속성 Durability
트랜잭션을 성공적으로 마치면 결과를 영구적으로 저장한다.
선언 방법
메소드, 클래스, 인터페이스 위에 선언한다.
적용된 범위에서는 트랜잭션 기능이 포함된 프록시 객체가 생성되어 자동으로 commit/rollback을 실행한다.
프록시 객체에서 접근 가능한 레벨로 지정해야 한다. (private 사용 불가)
트랜잭션은 객체 외부에서 처음 진입하는 메서드를 기준으로 동작한다.
Kotlin
1
2
@Transactional
fun signUp()속성 설정
Kotlin
1
@Transactional(propagation = Propagation.REQUIRED)트랜잭션 전파
트랜잭션 동작 도중에 다른 트랜잭션을 호출할 때 어떻게 할 것인지 설정한다.
REQUIRED: 진행 중인 트랜잭션이 있으면 참여하고, 없으면 새로운 트랜잭션을 생성한다.
SUPPORTS: 진행 중인 트랜잭션이 있으면 참여하고, 없으면 트랜잭션을 없이 작업을 진행한다.
MANDATORY: 진행 중인 트랜잭션이 있으면 참여하고, 없으면 예외를 발생시킨다. 독립적인 작업을 하면 안될 때 사용한다.
REQUIRES_NEW: 항상 새로운 트랜잭션을 생성한다. 진행 중인 트랜잭션이 있으면 보류시키고 해당 트랜잭션을 실행시킨다.
NOT_SUPPORTED: 트랜잭션 없이 작업을 진행한다. 진행 중인 트랜잭션이 있으면 보류시킨다.
NEVER: 트랜잭션 사용 금지. 진행 중인 트랜잭션이 있다면 예외를 발생시킨다.
NESTED: 진행 중인 트랜잭션이 있으면 중첩된 트랜잭션을 생성하고, 없으면 새로운 트랜잭션을 생성한다.
중첩된 트랜잭션은 부모 트랜잭션에서 발생하는 커밋과 롤백에 영향을 받지만, 부모 트랜잭션은 중첩된 트랜잭션에 영향을 받지 않는다.
Kotlin
1
@Transactional(isolation = Isolation.DEFAULT)트랜잭션 격리 수준(Isolation Level)을 설정한다.
트랜잭션에서 일관성이 없는 데이터를 접근할 수 있게 허용하는 수준을 설정한다.
Isolation Level이 낮아질 수록 동시성이 높아지고, 무결성이 낮아져 문제가 발생할 가능성이 커진다.
DEFAULT: 기본 격리 수준
READ_UNCOMMITTED
Level 0
SELECT가 수행된 데이터에 Shared Lock이 걸리지 않는다.
변경 사항이 완료(commit)되기 전에 다른 트랜잭션이 해당 행을 읽을 수 있다.
A 트랜잭션이 변경하고 완료하지 않은 데이터(Uncommitted or Dirty)를 B 트랜잭션이 읽을 수 있다.
Dirty Read, Non-Repeatable Read, Phantom Read 발생 가능
READ_COMMITTED
Level 1. Read Lock
가장 많이 선택되는 격리 수준. 오라클 DBMS 기본값
SELECT가 수행된 행에 Record Lock이 걸려서 변경 사항이 완료되기 전까지 다른 트랜잭션이 읽을 수 없다.
A 트랜잭션이 변경한 데이터를 완료하기 전까지 B 트랜잭션이 해당 데이터를 SELECT할 수 없다.
B 트랜잭션은 변경 전 데이터(Undo 영역에 백업된 데이터)를 SELECT 한다.
MVCC(Multi Version Consurrency Control) 변경 방식을 사용
Non-Repeatable Read, Phantom Read 발생 가능
REPEATABLE_READ
Level 2. Gap Lock
MySQL InnoDB Storage Engine 기본값
동일한 SELECT 문장을 수행했을 때 항상 같은 결과를 보장한다. (정합성)
A 트랜잭션이 완료되기 전까지 B 트랜잭션은 SELECT, UPDATE, DELETE를 할 수 없다.
INSERT는 가능하기 때문에 동일 트랜잭션에서 Read되는 row 수가 달라질 수 있다.
Phantom Read 발생 가능하지만 MySQL-InnoDB에서는 MVCC 특성에 의해 발생하지 않음
SERIALIZABLE
Level 3
가장 단순하면서 가장 엄격한 격리 수준
A 트랜잭션이 완료되기 전까지 B 트랜잭션은 어떠한 작업도 수행하지 못한다.
DeadLock에 걸리기 쉽다.
Kotlin
1
@Transactional(noRollbackFor = [SafeException::class])예외 제외. 특정 예외 발생 시 Rollback하지 않는다.
Kotlin
1
@Transactional(rollbackFor = [UserCustomException::class])예외 추가. 특정 예외 발생 시 Rollback한다.
Kotlin
1
@Transactional(timeout = TransactionDefinition.TIMEOUT_DEFAULT)트랜잭션 수행 시간을 제한한다. 지정한 시간 내에 작업이 완료되지 않으면 Rollback한다.
default: -1 (no timeout)
Kotlin
1
@Transactional(readOnly = true)읽기 전용 트랜잭션. 트랜잭션 내에서 데이터를 조작할 수 없다.
true로 설정하면 INSERT, UPDATE, DELETE 실행 시 예외를 발생시킨다.
default: false
REPEATABLE READ Test

REPEATABLE-READ.jpg
Reference

Google Analytics 4 개념 입문
Google Analytics 4 개념에 대해서 설명하는 글입니다.
ETC

Nuxt.js에 Sentry 적용하기
Nuxt.js 에서 Sentry 설정하기
Java Script
