트랜잭션
개념
- 데이터베이스가 제공하는 트랜잭션은 두 작업이 모두 성공해야 저장하고, 중간에 하나라도 실패 시 전의 상태로 돌아가게 됨
- 모두 성공 시
Commit을 통해 정상 반영되고, 실패해서 이전으로 RollBack을 통해 되돌릴 수 있음
트랜잭션 ACID
- 원자성 : 트랜잭션 내에서 실행한 작업은 모두 성공하거나 모두 실패해야함
- 일관성 : 모든 트랜잭션은 일관성 있는 데이터베이스 상태를 유지해야함
- 지속성 : 트랜잭션을 성공적으로 끝낼 시 결과가 항상 기록되어야 하고 중간에 문제 발생 시 로그 등을 사용하여 성공한 트랜잭션을 복구 가능해야 함
- 격리성 : 동시에 실행되는 트랜잭션이 서로에게 영향을 미치지 않도록 격리해야 함, 트랜잭션 격리 수준을 선택할 수 있음
-> 격리성을 완벽하게 보장하려면 트랜잭션을 순서대로 실행해야 하는데, 병렬처리가 안되므로 동시 처리 성능이 나빠지므로 격리 수준을 설정해야 함
트랜잭션 격리 수준
- READ UNCOMMITED: 커밋되지 않은 읽기- 데이터를 변경 중이고 커밋하지 않은 상태에서 데이터 읽기가 가능하므로 문제가 발생할 수 있음
- READ COMMITED: 커밋된 읽기
- REPEATABLE READ: 반복 가능한 읽기
- SERIALZABLE: 직렬화 가능
DB 세션
- 커넥션 생성 시 데이터베이스 서버는 내부에 세션을 만들고 모든 요청이 세션을 통해 실행됨
- 사용자가 커넥션을 닫거나 관리자가 세션 강제 종료 시 종료됨
트랜잭션 동작
- 쿼리 실행하고 데이터베이스에 결과 반영하려면
commit, 결과 반영하고 싶지 않을 경우 rollback 호출
- 커밋 호출하기 전까지는 임시로 데이터를 저장하고 다른 세션 사용자에게는 해당 데이터가 보이지 않음
- 커밋하지 않은 데이터를 다른 세션에서 조회 가능할 경우,
Rollback을 수행하면 커밋하지 않은 상태에서 변경한 데이터가 사라지기 때문에 데이터 정합성에 문제 발생
- 세션1에서 신규 데이터를 추가한 후에
commit을 호출하면 세션2에서도 조회 가능
- 세션1에서 데이터 추가 후
rollback 호출 시 트랜잭션 시작하기 직전의 상태로 복구됨
자동 커밋과 수동 커밋
- 자동 커밋: 각각의 쿼리를 실행할 때마다 실행 직후에 자동으로 커밋 호출 -> 커밋,롤백을 직접 호출하지 않아도 되지만 트랜잭션 기능을 사용하기 어려움
- 자동 커밋이 기본적으로 설정되어 있는데 수동 커밋 모드로 설정해야함
- 수동 커밋 설정 시 이후에 꼭 commit, rollback을 호출해야 함
- 한번 커밋 모드를 설정 시 해당 세션에서 계속 유지되며 중간에 변경 가능
- 수동 커밋으로 변경 시 트랜잭션이 시작된다고 할 수 있음
계좌이체 예제
데이터 : memberA -10000원, memberB - 10000원
- 상황1: 계좌이체 정상
- 세션1에서 멤버A의 돈을 멤버B에게 2000원 계좌이체하는 트랜잭션을 실행하면 자동으로 커밋되기 때문에 계좌이체가 정상적으로 진행됨
- 상황2: 계좌이체 문제 상황 - 커밋
- 계좌이체 진행하는 도중에 멤버A의 돈이 빠져나가는 것만 적용되고 멤버B에게 이체되는 쿼리는 오류가 발생해서 반영이 안되는 상태에서 자동으로 커밋됨 -> 계좌이체가 실패했지만 A의 돈이 빠져나가는 것만 적용됨
- 상황3: 계좌이체 문제 상황 - 롤백
- 롤백을 호출해서 계좌이체 실행 전으로 돌아와야함
DB 락
개념
- 동시에 데이터를 수정할 때 발생하는 문제를 해결
- 데이터를 변경하려고 할 때 해당 로우의 락을 획득해야함 -> 다른 세션에서 데이터를 변경하고자 하는데 락이 없으면 락이 돌아올 때까지 대기해야 하며, 대기 시간을 넘어가면 타임아웃 오류 발생
- 락이 있는 세션에서 트랜잭션 종료 시에 락을 반납하게 되며, 다른 세션에서 락을 획득할 수 있게 됨
SET LOCK_TIMEOUT <milliseconds> : 락 획득 시간을 설정 하고 시간 안에 락을 얻지 못하면 예외 발생
락 조회
- 일반적 조회에서는 락을 사용하지 않음 -> 세션1에서 락 획득하고 변경하고 있어도 세션2에서 조회 가능
select for update : 데이터 조회할 때 락을 획득하고 싶을 때 사용
- 조회 시점에 락이 필요한 경우: 트랜잭션 종료 시점까지 해당 데이터가 변경되면 안될 때 사용