이 글은 인프런 김영한님의 Spring 강의를 바탕으로 개인적인 정리를 위해 작성한 글입니다.
트랜잭션의 기본적인 내용은 아래의 글을 참고
2023.08.20 - [Java Category/Java] - [Java] DB 트랜잭션 처리
트랜잭션 ACID
ACID 속성
- 원자성(Atomicity): 트랜잭션 내의 모든 연산은 전부 완료되거나 전부 실행되지 않아야 한다는 원칙이다. 즉, 트랜잭션의 연산 중 하나라도 실패하면, 이미 실행된 모든 연산을 취소(롤백)하고, 전체 트랜잭션을 실패로 처리해야 한다.
- 일관성(Consistency): 트랜잭션이 실행되기 전과 후의 데이터베이스 상태는 일관된 상태를 유지해야 한다. 이는 트랜잭션이 데이터베이스의 모든 제약 조건을 충족시켜야 함을 의미한다. 예를 들어, 트랜잭션 동안 모든 데이터베이스 규칙과 제약 조건이 계속해서 만족되어야 한다.
- 독립성(Isolation): 동시에 여러 트랜잭션이 실행될 때, 각 트랜잭션은 서로 독립적으로 실행되어야 한다. 이는 한 트랜잭션이 다른 트랜잭션의 중간 실행 결과를 볼 수 없도록 보장해야 함을 의미한다. 독립성은 다양한 격리 수준을 통해 구현될 수 있다.
- 지속성(Durability): 트랜잭션이 성공적으로 완료되면, 그 결과는 시스템에 영구적으로 반영되어야 한다. 시스템에 장애가 발생하더라도, 이러한 변경 사항은 보존되어야 한다. 이는 데이터베이스 시스템이 장애로부터 복구된 후에도 트랜잭션 결과가 유실되지 않음을 보장한다.
ACID 속성 중 하나를 제외한 경우
ACID 속성 중 하나를 제외하고 시스템을 운영하게 되면, 데이터의 무결성, 신뢰성 및 시스템의 안정성에 심각한 문제가 발생할 수 있다. 각 속성이 제외될 때 발생할 수 있는 문제를 구체적으로 살펴보자.
원자성(Atomicity)이 제외된 경우
원자성이 보장되지 않으면, 트랜잭션 중 일부 연산만 성공적으로 완료되고 나머지는 실패할 수 있다. 이는 데이터의 일관성을 파괴하며, 데이터베이스가 부분적으로만 업데이트되어 부정확한 상태로 남을 수 있다. 예를 들어, 은행 계좌 이체 과정에서 금액을 출금하는 연산은 성공했으나 입금하는 연산은 실패하면, 금액이 사라지는 문제가 발생할 수 있다.
일관성(Consistency)이 제외된 경우
일관성이 보장되지 않으면, 트랜잭션 실행 후 데이터베이스의 상태가 모델의 규칙이나 제약 조건을 위반할 수 있다. 이는 데이터의 신뢰성을 저하시키며, 시스템의 예측 불가능한 동작을 초래할 수 있다. 예를 들어, 제약 조건을 무시하고 음수 잔액을 가진 계좌를 허용할 수 있다.
독립성(Isolation)이 제외된 경우
독립성이 보장되지 않으면, 여러 트랜잭션이 동시에 실행될 때, 한 트랜잭션의 중간 결과가 다른 트랜잭션에 의해 볼 수 있게 되어 데이터의 일관성이 손상될 수 있다. 이는 "더티 리드(Dirty Read)"와 같은 현상을 일으키며, 최종적으로 잘못된 데이터를 생성할 수 있다.
지속성(Durability)이 제외된 경우
지속성이 보장되지 않으면, 트랜잭션이 성공적으로 완료된 후에도 시스템 장애가 발생할 경우 해당 트랜잭션의 결과가 손실될 수 있다. 이는 데이터 손실로 이어지며, 복구가 어려울 수 있다. 예를 들어, 시스템이 트랜잭션 로그를 디스크에 쓰지 않고 장애가 발생하면, 그 사이에 실행된 모든 트랜잭션 데이터가 유실될 수 있다.
각 ACID 속성은 데이터베이스의 안정적인 운영을 위해 상호 의존적이며, 이 중 하나라도 결여되면 시스템 전체의 신뢰성과 정확성이 크게 저하될 수 있다. 따라서, 모든 속성을 적절히 관리하고 보장하는 것이 중요하다.
데이터베이스의 격리 수준(Isolation Level)
트랜잭션들이 데이터를 공유할 때 서로 영향을 주고받는 정도를 결정한다. 격리 수준은 데이터베이스의 동시성과 일관성 사이의 균형을 조절하는 중요한 역할을 하며, 다양한 격리 수준은 서로 다른 성능 및 ACID 속성에 대한 보장을 제공한다. 이러한 격리 수준에는 READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ, SERIALIZABLE 등이 있다.
READ UNCOMMITTED (읽기 미확정)
성능: 가장 높은 성능을 제공한다. 이는 트랜잭션들이 다른 트랜잭션의 확정되지 않은 변경 내용까지 읽을 수 있기 때문이다.
ACID 영향: 가장 낮은 격리 수준으로, 다른 트랜잭션에 의해 변경되었으나 아직 커밋되지 않은 데이터를 읽을 수 있어, "더티 리드(Dirty Read)" 문제가 발생할 수 있다. 이는 일관성(Consistency)을 저해할 수 있다.
READ COMMITTED (읽기 확정)
성능: READ UNCOMMITTED보다는 낮지만, 일반적으로 좋은 성능과 균형을 제공한다.
ACID 영향: "더티 리드" 문제를 방지할 수 있으며, 커밋된 데이터만 읽을 수 있다. 하지만, 같은 트랜잭션 내에서 동일한 쿼리를 두 번 실행하면 다른 결과를 얻을 수 있는 "Non-repeatable Read" 문제가 발생할 수 있다.
Non-repeatable Read
ACID 속성 중 일관성(Consistency)과 관련된 문제로, 한 트랜잭션 내에서 같은 데이터를 두 번 조회했을 때, 두 조회 결과가 서로 다른 값을 반환하는 현상을 말한다. 이 문제는 주로 다른 트랜잭션이 동시에 동일한 데이터를 수정할 때 발생한다.
예를 들어, 트랜잭션 A가 어떤 데이터를 조회한 후, 같은 트랜잭션 내에서 동일한 데이터를 다시 조회하기 전에 트랜잭션 B가 그 데이터를 수정하고 커밋한다면, 트랜잭션 A의 첫 번째와 두 번째 조회 결과는 다를 것이다. 이러한 현상은 데이터베이스의 독립성(Isolation) 속성에 대한 위배로 간주될 수 있으며, 트랜잭션이 서로 격리되지 않아 발생하는 문제이다.
REPEATABLE READ (반복 가능 읽기)
성능: READ COMMITTED보다는 낮은 성능을 제공할 수 있다. 이는 트랜잭션이 실행되는 동안 조회한 데이터에 대해 다른 트랜잭션의 변경을 방지하기 때문이다.
ACID 영향: "Non-repeatable Read" 문제를 방지한다. 하지만, 다른 트랜잭션에 의해 새로 삽입된 데이터를 볼 수 있어 "팬텀 리드(Phantom Read)" 문제가 발생할 수 있다.
Phantom Read
데이터베이스 트랜잭션에서의 격리 수준(Isolation Level)과 관련된 현상으로, 한 트랜잭션 내에서 동일한 쿼리를 두 번 실행했을 때, 첫 번째 쿼리와 두 번째 쿼리의 결과가 다른 행(레코드)를 포함하는 경우를 말한다. 이는 다른 트랜잭션이 첫 번째와 두 번째 쿼리 실행 사이에 새로운 데이터를 삽입하거나 삭제함으로써 발생한다.
예를 들어, 트랜잭션 A가 특정 조건에 맞는 레코드들을 조회하는 쿼리를 실행하고, 이후 같은 트랜잭션 내에서 동일한 쿼리를 다시 실행했을 때, 트랜잭션 B가 첫 번째와 두 번째 쿼리 실행 사이에 해당 조건에 맞는 새로운 레코드를 삽입하면, 트랜잭션 A의 두 번째 쿼리 결과에는 처음에는 없던 새로운 레코드가 포함되게 된다. 이러한 현상을 팬텀 리드라고 한다.
SERIALIZABLE (직렬화 가능)
성능: 가장 엄격한 격리 수준으로, 성능 저하가 가장 크다. 이는 트랜잭션이 완전히 독립적으로 실행되어야 하며, 동시성이 크게 제한되기 때문이다.
ACID 영향: "팬텀 리드"를 포함한 모든 동시성 문제를 방지한다. 이 격리 수준에서는 트랜잭션이 다른 트랜잭션의 영향을 전혀 받지 않아 가장 높은 수준의 일관성을 보장한다.
읽기 미확정이 가장 낮은 격리 수준이고, 직렬화 가능이 가장 높은 격리 수준이다.
각 격리 수준은 동시성과 데이터 일관성 사이의 트레이드오프를 나타낸다. 높은 격리 수준은 더 나은 ACID 속성의 보장을 제공하지만, 동시성이 제한되어 성능에 영향을 줄 수 있다. 반대로 낮은 격리 수준은 더 높은 동시성과 성능을 제공하지만, 데이터 일관성 문제를 유발할 수 있다. 따라서, 애플리케이션의 요구 사항과 데이터 일관성의 중요도를 고려하여 적절한 격리 수준을 선택하는 것이 중요하다.
Trade-off
트레이드 오프(Trade-off)는 서로 상충하는 두 가지 이상의 목표나 조건 사이에서 선택을 해야 할 때, 한 쪽의 이득을 얻기 위해 다른 한 쪽을 포기하는 상황을 말한다. 즉, 어떤 선택을 할 때 발생하는 비용과 이득 사이의 균형을 의미한다.
일반적으로는 READ COMMITTED(커밋된 읽기) 트랜잭션 격리 수준을 많이 사용한다.
데이터베이스 연결 구조와 DB 세션
데이터베이스 연결 구조와 데이터베이스 세션은 데이터베이스 관리 시스템(DBMS)에서 중요한 개념이다.
이들은 클라이언트 애플리케이션과 데이터베이스 서버 간의 상호 작용을 가능하게 하는 기본적인 메커니즘을 제공한다.
데이터베이스 연결 구조
데이터베이스 연결 구조는 클라이언트 애플리케이션과 데이터베이스 서버 간의 통신 경로를 설정하는 방법을 말한다. 이 연결을 통해 클라이언트는 SQL 명령을 데이터베이스 서버로 전송할 수 있고, 서버는 이러한 명령을 실행한 후 결과를 클라이언트에게 반환한다.
연결은 일반적으로 TCP/IP 네트워크 프로토콜을 사용하여 이루어진다. 보안을 위해 SSL/TLS와 같은 암호화 프로토콜을 사용하여 데이터를 안전하게 전송할 수 있다.
클라이언트 애플리케이션은 데이터베이스 서버에 대한 연결을 맺을 때마다 상당한 오버헤드가 발생할 수 있다. 이를 최소화하기 위해 커넥션 풀을 사용한다. 커넥션 풀은 미리 정의된 수의 데이터베이스 연결을 유지하고, 필요할 때마다 이러한 연결을 재사용함으로써 연결 및 해제에 따른 오버헤드를 줄인다.
사용자는 웹 애플리케이션 서버(WAS)나 DB 접근 툴 같은 클라이언트를 사용해서 데이터베이스 서버에 접근할 수 있다.
클라이언트는 데이터베이스 서버에 연결을 요청하고 커넥션을 맺게 된다.
이때 데이터베이스 서버는 내부에 세션을 만든다. 그리고 앞으로 해당 커넥션을 통한 모든 요청은 이 세션을 통해서 실행하게 된다.
쉽게 이야기해서 개발자가 클라이언트를 통해 SQL을 전달하면 현재 커넥션에 연결된 세션이 SQL을 실행한다. 세션은 트랜잭션을 시작하고, 커밋 또는 롤백을 통해 트랜잭션을 종료한다. 그리고 이후에 새로운 트랜잭션을 다 시 시작할 수 있다.
사용자가 커넥션을 닫거나, 또는 DBA(DB 관리자)가 세션을 강제로 종료하면 세션은 종료된다.
커넥션 풀이 10개의 커넥션을 생성하면, 세션도 10개 만들어진다.
데이터베이스 세션
데이터베이스 세션은 클라이언트 애플리케이션과 데이터베이스 서버 간의 지속적인 대화나 상태를 유지하는 기간을 말한다.
세션은 클라이언트가 데이터베이스 서버에 연결을 맺은 후 시작되며, 클라이언트가 연결을 명시적으로 해제하거나, 타임아웃이 발생할 때 종료된다.
- 세션 상태: 데이터베이스 세션 동안, 서버는 클라이언트의 로그인 정보, 트랜잭션 상태, 설정 등 세션별 상태 정보를 유지한다. 이를 통해 클라이언트는 여러 데이터베이스 작업을 연속적으로 수행할 수 있으며, 각 작업은 동일한 세션 상태를 공유한다.
- 트랜잭션 관리: 세션 내에서 발생하는 여러 트랜잭션은 동일한 세션 컨텍스트 내에서 관리된다. 이는 트랜잭션의 ACID 속성을 보장하는 데 중요하다.
데이터베이스 연결 구조와 세션의 관리는 애플리케이션의 성능, 확장성, 보안성에 직접적인 영향을 미친다. 따라서, 효율적인 연결 및 세션 관리는 데이터베이스 기반 애플리케이션을 설계하고 구현할 때 중요한 고려 사항이다.
'데이터베이스 > 데이터베이스 이론' 카테고리의 다른 글
[Database] 트랜잭션 락(Lock) (1) | 2024.02.28 |
---|---|
[DB 이론] 데이터베이스 정규화 (1) | 2023.12.10 |
[DB 이론] 데이터베이스 설계 (1) | 2023.12.09 |
[DB 이론] 관계 데이터 모델 (1) | 2023.12.08 |
[DB 이론] 데이터베이스 모델링 (2) | 2023.12.07 |