본문 바로가기
Back-End/도메인 주도 개발 시작하기

[DDD] 도메인 주도 개발 시작하기 Ch8

by ChaSso 2024. 4. 1.

Chapter 8 애그리거트 트랜잭션 관리

8.1 애그리거트와 트랜잭션

∘  운영자는 상품의 배송 상태를 바꾸고, 동시에 고객은 배송지 정보를 바꿈. 서로 다른 애그리거트 객체를 이용하지만 트랜잭션 커밋할 때 두 정보가 다 바뀜 → 애그리거트의 일관성이 깨짐
∘ 애그리거트 트랜잭션 처리 방식에는 선점 잠금과 비선점 잠금이 있음

 

8.2 선점 잠금

∘  선점 잠금 : 먼저 애그리거트를 구한 스레드가 애그리거트 사용이 끝날 때까지 다른 스레드가 해당 애그리거트를 수정하지 못하게 블로킹
∘  먼저 애그리거트를 사용하던 스레드가 수행하고 트랜잭션을 커밋하면 잠금이 해제됨
∘  데이터 충돌 문제 해결 가능
∘  선점 잠금은 보통 DBMS가 제공하는 행단위 잠금을 사용해서 구현
∘  JPA 프로바이더와 DBMS에 따라 잠금 모드 구현이 다름

8.2.1 선점 잠금과 교착 상태

∘  교착 상태 : 두 스레드가 각각 상대 스레드가 먼저 선점한 잠금을 구할 수 없음
∘  교착 상태의 발생을 막으려면 잠금을 구할 때의 최대 대기 시간을 지정해야 됨


8.3 비선점 잠금

∘  운영자가 배송 상태를 변경하는 사이에 고객이 배송지를 변경해버리는 상황은 선점 잠금으로 해결하지 못하는 상황
∘  비선점 잠금 : 동시에 접근하는 것을 막는 대신 변경한 데이터를 실제 DBMS에 반영하는 시점에 변경 가능 여부를 확인
∘  새로 커밋하려는 버전이 이미 커밋된 버전과 충돌하면 데이터 수정에 실패
∘  JPA는 버전을 이용한 비선점 잠금 기능을 지원함
∘  응용 서비스가 버전은 확인할 필요 없이 애그리거트 데이터가 변경되면 트랜잭션이 종료될 때 JPA가 비선점 잠금을 위한 쿼리 실행
∘  시스템은 애그리거트를 조회할 때 버전 값도 불러옴
∘  비선점 잠금 방식을 여러 트랜잭션으로 확장하려면 애그리거트 정보와 함께 버전 정보도 화면에 보여줘야 함
∘  응용 서비스에 보내는 요청 데이터에 사용자가 전송한 버전 값이 포함됨 → 응용 서비스가 그 버전 값과 애그리거트 버전이 일치하는지 확인 후에 일치하면 기능 수행
∘  표현 계층은 익셉션이 발생하면 사용자에게 버전 충돌이 발생했음을 알림

8.3.1 강제 버전 증가
∘  애그리거트 내에 있는 구성요소의 상태가 바뀌면 애그리거트의 버전 값이 증가해야 비선점 잠금이 올바르게 동작할 수 있음
∘  JPA는 엔티티를 구할 때 강제로 버전 값을 증가시키는 잠금 모드 지원. EntityManager#find()

 

8.4 오프라인 선점 잠금

∘  컨플루언스는 사전에 충돌 여부는 알려주지만 동시에 수정하는 것은 허용함
∘  누군가가 수정 화면을 보고 있을 때 수정 화면을 실행하지 못하도록 하려면 오프라인 선점 잠금 방식을 이용해야 됨
∘  선점 잠금 방식과 비선점 잠금 방식은 한 트랜잭션 범위에서만 적용되지만 오프라인 잠금 선점 잠금 방식은 여러 트랜잭션에 적용됨
∘  영원히 잠금을 구할 수 없는 상황을 막기 위해 잠금 유효 시간 필요

8.4.1 오프라인 선점 잠금을 위한 LockManager 인터페이스와 관련 클래스
∘  잠금 선점 시도, 잠금 확인, 잠금 해제, 잠금 유효시간 연장 기능이 필요
∘  LockManager 인터페이스
∘  tryLock() : 잠금을 구할 때. 잠금 식별을 위한 LockId 리턴
∘  LockManager#tryLock() : 오프라인 선점 잠금이 필요한 코드에서 잠금 시도할 때
∘  컨트롤러가 오프라인 선점 잠금 기능으로 데이터 수정 폼에 동시에 접근하는 것을 제어
∘  잠금 해제할 때 LockId 이용

8.4.2 DB를 이용한 LockManager 구현
∘  checkAlreadyLocked() : 이미 잠금이 선점되었는지 확인
∘  locking() : 잠금 선점
∘  isExpired() : 유효 시간이 지났는지