1.Transaction?
Transaction은 더이상 나눌 수 없는 작업의 단위다. Transaction대신 별칭 Tx로 자주 표현되며, Transaction의 종류로는 대표적으로 SQL에서 insert, update, select를 수행하는 작업이 있다. 만약 계좌이체를 한다고 하면 출금(update)과 입금(update)이 하나의 Tx로 묶여야한다. 하나의 Tx로 묶여한다는 의미는 하나의 작업단위가 되어야 한다는 말이다. 내 계좌에서 은행계좌로 1000만원을 입금한다고 가정해보자. 그러면 내 계좌에서는 1000만원이 빠져나가야하고 은행계좌에는 1000만원이 입금되어야한다. Transaction이 제대로 이뤄지면 결과적으로 내 계좌(-1000만원) 은행계좌(+1000만원)인 작업이 실행 될 거다. 그러나 만약 Transaction이 제대로 이뤄지지 않는다면 내 계좌 (-1000만원) 은행계좌(0) 결과 같이 1000만원이 공중에서 분해된다.
2.Transaction의 속성 - ACID
- 원자성(Atomicity) - 나눌 수 없는 하나의 작업으로 다뤄져야 한다.
계좌이체 예시 경우 출금과 입금이라는 두 개의 Tx로 작업이 된다. 하지만 계좌이체가 성공하기 위해서는 출금과 입금이라는 두 개의 Tx가 하나의 작업으로 다뤄져야한다. 이처럼 하나의 작업으로 다뤄져야 하는 Transaction의 속성을 원자성이라고 한다.
- 일관성(Consistency) - Tx 수행 전과 후가 일관된 상태를 유지해야 한다.
계좌이체를 진행할 때 내 계좌에서 은행 계좌로 1000만원을 입금한다고 하면 입금 전 후에 1000만원이 존재 해야한다. 즉 1000만원이라는 돈이 내 계좌에서 은행 계좌로 이동만했지 1000만원이라는 돈은 그대로 존재한다. 그러나 만약 일관성이 깨져 출금 전에는 갖고있던 1000만원이 출금 후에는 0원이 된다면 문제가 발생한다. 그래서 Tx은 작업이 진행되는 전과 후의 상태를 유지해야한다.
- 고립성(Isolation) - 각 Tx는 독립적으로 수행되어야 한다.
내 계좌에서 n사 은행계좌로 이체하고(Tx1) 내 동생이 자기 계좌에서 k사 은행계좌로 계좌이체(Tx2)를 한다고 가정하면, 두 작업은 서로에게 어떤 영향도 끼쳐선 안된다. 내 계좌에서 n사로 입금했던 행위가 내 동생 계좌로 입금된다거나, n사 은행 계좌로 입금했는데 k은행 계좌로 입금이 되면 문제가 발생한다. 그래서 Transaction의 작업은 독립적으로 수행되어야 한다.
- 영속성(Durability) - 성공한 Tx의 결과는 유지되어야 한다.
내 계좌에서 n사 은행계좌로 1000만원이 입금되었으면 n사의 은행계좌에는 1000뭔이 있어야한다. 만약 내가 1000만원을 n사 은행으로 입금했지만, n사 은행에 1000만원이 없다면 얼마나 황당할까?
3.커밋(commit)과 롤백(rollback)
커밋은 작업 내용을 DB에 영구적으로 저장하는 행위다. 만약 commit(1)이후의 작업들을 커밋(commit(2))를 해버리면 DB에는 작업 정보가 영구적으로 저장돼 commit(2) 이전의 작업으로 돌아 갈 수 없다. 만약 commit(1) 작업 이후 insert와 update는 commit을 하지 않으면 이전 작업으로 돌아 갈 수 있다. 최근 변경사항을 취소하는 행위 즉, 마지막 커밋으로 복귀하는 것을 롤백(rollback)이라 한다. 무엇보다 commit은 작업을 실행하기 전에 한번 commit을 해버리면 작업을 되돌릴 수 없기에 신중하게 해야한다.
- 커밋(commit) - 작업 내용을 DB에 영구적으로 저장
- 롤백(rollback) - 최근 변경사항을 취소(마지막 커밋으로 복귀)
3-1 자동커밋과 수동커밋
- 자동커밋
자동커밋은 작업 명령을 실행하면 자동으로 커밋되는 행위를 말한다. 만약 delete작업을 수행하면 자동으로 커밋된다. 그러면 두 번째 update로 작업을 되돌릴 수 없다. 즉 롤백이 불가능하다.
- 수동커밋
수동커밋은 자동커밋과는 다르게 작업 명령을 실행 한 후에는 명시적으로 commit또는 rollback을 입력해준다. 만약 자동커밋의 동작을 멈추고자 한다면 SET autocommit = 0; 명령어를 수행한다. 하나의 작업을 수행하는 경우 자동커밋이 유리하지만, 두 개 이상의 작업을 수행하는 경우에는 수동커밋을 쓰도록한다.
4.Tx의 isolation level
- READ UNCOMMITED - 커밋되지 않은 데이터도 읽기 가능
READ UNCOMMITED는 영어단어 의미 그대로 커밋되지 않은 데이터도 읽기 가능함을 뜻한다. 그림을 보면 Tx2에서 INSERT 명령문을 통해 '2,200' 데이터를 입력했다. 하지만 커밋은 하지 않았다. 커밋을 하지 않았기 때문에 Tx1에서 SELECT문을 입력하면 결과값으로 '1,100' 데이터 값만 포함된 결과 값이 나와야 된다고 생각하지만 READ UNCOMMITED는 커밋되지 않은 결과 값을 읽어서 '2,200'도 함께 나오는 결과 값을 보여준다. READ UNCOMMITED는 다른이름으로 dirty read라고도 한다. 여기서 뜻하는 dirty는 손을 많이 탔다는 의미다.
- READ COMMITED - 커밋된 데이터만 읽기 가능
READ COMMITED은 READ UNCOMMITED과 반대로 커밋된 데이터만 읽는다. Tx2에서 실행된 INSERT문 이후 Tx1의 SELECT문은 앞서 살펴본 READ UNCOMMITED과 달리 결과값에 커밋되지 않은 값이 저장되지 않는다. 비로소 commit명령어가 떨어져야 Tx1의 마지막 SELECT문을 보는 것 처럼 데이터가 저장된다.
- REPEATABLE READ - Tx의 시작 후 다른 Tx의 변경은 무시됨
REPETEABLE READ는 다른 트랜잭션에 영향을 받지 않는 독립성을 지닌다. 그림에서 보는 바와 같이 Tx1은 Tx2의 영향을 받지 않고 쭉 같은 결과 값으로 반복되는 걸 알 수 있다. REPEATABLE READ가 isolation에서 가장 기본 값으로 다른 isolation level은 여기서 파생된다.
- SERIALIZABLE - 한번에 하나의 Tx만 독립적으로 수행
SERIALIZABLE은 isolation level 가장 높다. SERIALIZABLE은 한번에 하나의 Tx만 수행되기 때문에 그림에서 처럼 먼저 수행된 Tx1의 작업이 마무리 되기 전 까지 다른 Tx는 진행되지 않는다. Tx1에서 '1,100' 데이터가 들어있는 값을 꺼내는 작업이 진행되는 동안 Tx2에서는 INSERT 작업이 수행됐다. 하지만 아직 Tx1의 작업이 commit되지 않았기 때문에 Tx2의 INSERT문은 대기 상태에 있고 Tx1에서 작업이 끝난 commit을 실행해야지 그제서야 INSERT문이 작동된다. SERIALIZABLE은 데이터가 엉키면 안되는 경우 사용한다. 하나의 Tx 수행을 끝내고 다른 Tx의 수행을 진행하기 때문에 효율성 떨어지지만 데이터의 품질은 올라간다.
출처:스프링의 정석 : 남궁성과 끝까지 간다(패스트 캠퍼스 강좌)
'Spring > Spring DI와 AOP' 카테고리의 다른 글
[Spring DI와 AOP]@Transactional (0) | 2022.07.30 |
---|---|
[Spring DI와 AOP] DAO (0) | 2022.03.12 |
[Spring AOP] AOP의 개념과 사용 (0) | 2022.03.07 |
[Spring DI] BeanFactory / ApplicationContext 와 IoC / DI (0) | 2022.02.28 |