트랜잭션은 DB 작업의 나누어지지 않는 최소 단위이다.
쉽게 말해 한꺼번에 수행되어야 할 연산을 모아놓은 것
트랜잭션 4가지 특징 (ACID)
1) Automicity (원자성)
•
트랜잭션의 내용이 DB에 모두 반영되거나, 모두 반영되지 않아야 한다.
2) Consistenty (일관성)
•
트랜잭션 작업의 결과는 항상 일관성이 있어야 한다.
•
시스템이 가지고 있는 고정 요소는 트랜잭션이 실행되기 전과 실행된 후 모두 같아야 한다.
ex) DB의 상태, 컬럼의 타입 등
3) Isolation (격립성)
•
둘 이상의 트랜잭션이 동시에 병행 실행되고 있을 때, 어떤 트랜잭션도 다른 트랜잭션의 연산에 관여할 수 없다.
4) Durability (지속성)
•
트랜잭션이 성공적으로 완료되었다면, 그 결과는 영구적으로 반영되어야 한다.
트랜잭션의 연산
1) COMMIT 연산
•
트랜잭션의 연산이 성공적으로 수행되었음을 선언하는 연산
•
트랜잭션의 결과를 DB에 반영한다.
2) ROLLBACK 연산
•
트랜잭션의 수행이 실패했음을 선언하고 작업을 취소하는 연산
◦
트랜잭션 연산 중 일부가 실패되었다면, ROLLBACK을 통해 트랜잭션 수행 전의 상태로 DB를 되돌린다.
DB 격리성 수준
1.
Read Uncommitted
트랜잭션에서 처리 중인(아직 커밋처리되지 않은) 데이터를 다른 트랜잭션에서 읽는 것을 허용한다. Dirty-Read, Non-Repeatable Read, Phantom Read 문제가 발생할 수 있다.
2.
Read Committed
트랜잭션이 커밋되어 확정된 데이터에 대해서만 다른 트랜잭션이 읽도록 허용한다. 커밋되지 않은 데이터는 실제 DB 데이터가 아닌 Undo 로그에 있는 이전 데이터를 읽어온다.
따라서, Non-Repeatable Read, Phantom Read 문제는 발생할 수 있다.
3.
Repeatable Read
트랜잭션에서 조회를 했을 때 항상 같은 결과를 반환하는것을 보장하는 격리 수준이다.
트랜잭션에서 조회를 했을 때 데이터를 UNDO 영역에 데이터를 백업해 놓는다.
이후에 같은 트랜잭션에서 조회를 한번 더 했을 때 결과의 트랜잭션 아이디가 자신의 트랜잭션 아이디보다 높다면 Undo log에서 데이터를 읽어온다.
하지만 DB 프로그램에 따라 Phantom Read문제는 발생할 수 있다.
InnoDB 스토리지 엔진(MySQL) 은 갭 락과 넥스트 키 락 덕분에 REPEATABLE READ 격리 수준에서도 PHANTOM READ 문제가 발생하지 않는다. 때문에 InnoDB를 사용한다면 이후 나올 SERIALIZABLE 격리 수준을 사용할 필요성은 없다고 한다.
4.
Serializable Read
트랜잭션에서 쿼리를 두 번 이상 실행했을 때, 첫번째 쿼리의 결과 레코드가 사라지거나 값이 바뀌지않음, 또 새로운 레코드가 나타나지 않도록 하는 설정
→ 결론은 무적이다.
격리성으로 인해 나타날 수 있는 문제점
Dirty Read
다른 트랜잭션에 의해 수정됐지만 아직 커밋되지 않은 데이터를 읽어서 발생하는 문제
값을 수정하는 트랜잭션이 중간에 실패하여 Rollback될 경우 다른 트랜잭션에서는 이미 수정된 데이터를 읽어 잘못된 값을 가지고 로직을 처리하는 문제가 발생한다.
Non-Repeatable Read
한 트랜잭션 내에서 같은 key값을 가진 Row를 두번 읽었는데 그 사이에 값이 변경되거나 삭제되어 결과가 다르게 나타나는 현상
Phantom Read
Non-Repeatable Read와 일부 반대되는 개념
한 트랜잭션에서 같은 쿼리를 두번 수행했는데 첫번째 쿼리에서는 없던 row가 생겨 두번째 쿼리에서 유령 record를 읽는 경우
Non-Repeatable Read는 1개의 Row의 데이터의 값이 변경되는 것이며 Phanton Read는 다건을 요청하는 것에 대해서 데이터의 값이 변경되는 것이다.
트랜잭션의 크기
트랜잭션의 크기가 성능과 일관성에 미치는 영향에 대해 알아보자.
트랜잭션의 크기란 트랜잭션 내에서 수행되는 작업의 양이나 데이터의 범위를 의미한다.
트랜잭션의 크기를 조절하는 것은 성능과 데이터의 무결성에 많은 영향을 미친다.
트랜잭션이 클 경우
트랜잭션의 크기가 크다면 많은 작업을 한 번에 처리할 수 있어 논리적으로 이어져야할 작업들을 한 번에 처리할 수 있기 때문에 데이터의 일관성을 유지하는데는 도움이 된다.
하지만 한 트랜잭션에서 여러 데이터에 대해 작업을 처리하여 처리하는 시간이 길어질 수록 DB 락을 오래 물고 있는 것이기 때문에 경합 문제를 야기할 수 있다.
또한 데이터베이스의 커넥션 풀도 빠듯하게 사용하게 된다. 그리고 작업이 실패했을 시 롤백 작업에 소모되는 자원이 많아진다.
•
장점
◦
여러 데이터를 한 번에 처리할 수 있어 데이터의 일관성을 유지하기 좋다.
•
단점
◦
DB 락을 오래 물고 있기 때문에 경합 문제가 발생할 가능성이 크다.
◦
DB 락을 오래 물고 있기 때문에 DB에 연결되는 커넥션 수가 증가하여 커넥션 풀를 관리하기 힘들다
◦
롤백 시 많은 자원을 소모하게 된다.
트랜잭션이 작을 경우
트랜잭션의 크기가 작을 경우 한 트랜잭션이 처리되는 시간이 짧아 DB 락을 짧은 시간만 유지하므로 성능적으로 유리하다.
하지만 트랜잭션의 커밋이 많아져 오버헤드가 발생할 가능성이 높다.
또한 하나의 논리적인 단위로 처리되어야 할 작업이 여러 트랜잭션으로 나뉘게 되면 보상 트랜잭션같은 처리 방법이 필요하고 데이터의 일관성을 지키기 까다로워진다.
•
장점
◦
DB에 대해 락을 짧게 유지하여 다른 트랜잭션이 더 빨리 접근할 수 있어 동시성이 높아진다.
◦
트랜잭션 충돌 및 데드 락 상태가 줄어든다.
◦
트랜잭션 실패 시 롤백 작업의 비용이 작다.
•
단점
◦
서로 관련된 작업들이 작은 트랜잭션으로 나뉘기 때문에 데이터의 일관성을 유지하기 어렵다.
◦
트랜잭션 관리가 복잡해진다 ex) 재시도, 오류처리, 보상 트랜잭션 등
◦
트랜잭션이 빈번하게 발생하면 각 트랜잭션 처리 과정에서 발생하는 커밋, 로그 기록 등의 작업이 시스템의 성능을 떨어트릴 수 있다. 즉, 오버헤드가 발생하여 성능이 낮아진다.