본문 바로가기

책리뷰/도메인 주도 개발 시작하기(DDD핵심 개념 정리부터 구현까지)

도메인 주도 개발(DDD) 애그리거트 트랜잭션 관리

728x90
반응형

목차

    애그리거트와 트랜잭션

    • 한 주문 애그리거트에 대해 운영자는 배송상태로 변경하고 사용자는 배송지 주소를 변경하면?

    • 트랜잭션마다 리포지터리는 새로운 애그리거트 객체를 생성하므로 운영자 스레드와 고객스레드는 같은 주문 애그리거트를 나타내는 다른 객체를 구하게됨 
    • 개념적으로 동일한 애그리거트지만 물리적으로 다른 애그리거트 객체를 사용
    • 애그리거트의 일관성이 깨짐
      • 운영자가 배송지 정보 조회 후 상태 변경하는 동안 고객이 수정하지 못하게 해야함
      • 운영자가 정보조회 이후 고객이 변경하면 운영자가 다시 조회한 후 수정 
    • 위 두 가지 방법은 트랜잭션 처리 기법이 필요함 

    선점 잠금

    • 먼저 애그리거트를 구한 스레드가 사용이 끝날때까지 다른 스레드가 해당 애그리거트 수정을 못하게 막음 

    • 스레드2는 스레드1이 잠금해제할 때까지 블로킹

    • 선점잠금은 다수의 DBMS가 for update와 같은 쿼리를 사용해 특정 레코드에 한 커넥션만 접근할 수 있는 잠금잠치를 제공 

     

    Order order = entityManager.find(Order.class, LockModeType.PESSIMISTIC_WRITE);
    • JPA EntityManager는 LockModeType을 인자로 받는 find()메서드를 제공함 

     

    • 스프링 데이터 JPA는 @Lock 애너테이션을 사용해 잠금 모드를 지정 

     

    선점잠금과 교착상태

    • 스레드1과 스레드2는 교착상태에 빠진다.
    • 이 문제가 발생하지 않도록 하려면 최대 대기시간을 지정해야한다. 

     

     

    • JPA에서 선점 잠금시도할 때 대기 시간을 지정하려면 힌트를 사용한다.
    • JPA의 'javax.persistence.lock.timeout'힌트는 잠금을 구하는 대기시간을 밀리초 단위로 지정 
    • DBMS에 따라 힌트가 적용되지 않을 수도 있음 

     

    • 스프링 데이터 JPA는 @QueryHints 애너테이션을 사용해서 지정할 수 있음 

     


    비선점 잠금

    • 선점 잠금으로 모든 트랜잭션 충돌 문제가 해결되는 것은 아님 

    • 운영자가 배송지 정보 조회 후 배송상태로 변경하는 동안 고객이 배송지를 변경할 경우 
    • 선점 잠금으로 해결할 수 없음 > 비선점 잠금 
    • 비선점 잠금이란? 동시에 접근하는 것을 막는 대신 변경한 데이터를 실제 DBMS에 반영하는 시점에 변경가능 여부를 확인하는 방식 


    • 수정할 애그리거트와 매핑되는 테이블의 버전 값이 현재 애그리거트의 버전과 동일한 경우에만 데이터 수정 
    • 수정에 성공하면 버전 값을 1증가 

    • JPA는 버전을 이용한 비선점 잠금 기능을 지원함
    • @Version 애너테이션을 붙이고 매핑되는 테이블에 버전을 저장할 컬럼을 추가하면 됨 
    • Update 쿼리 실행할 때 @Version에 명시한 필드를 이용해서 비선점 잠금 쿼리를 실행함 

     

    • 응용서비스는 버전에 대해 알 필요가 없음 

    • 과정2에서 운영자는 배송 상태 변경 요청시 과정1을 통해 받은 애그리거트 버전값을 함께 전송 
    • 과정 1에서 받은 버전A와 과정2.1을 통해 얻은 애그리거트 버전 B가 다르면 1과 과정2사이에 다른 사용자가 애그리거트를 수정한 것임 

     

    • 표현 계층은 버전 충돌 익셉션이 발생하면 버전 충돌을 사용자에게 알려 사용자가 알맞은 후속 처리를 할 수 있도록 함 

     

    강제 버전 증가

    • 루트엔티티의 값이 바뀌지 않았더라도 애그리거트 구성요소 중 일부 값이 바뀌면 논리적으로 애그리거트 버전값이 올라가야 함 

    • JPA는 강제로 버전 값을 증가시키는 잠금 모드를 지원함
    • LockModeType.OPTIMISTIC_FORCE_INCREMENT 사용시 엔티티 상태가 변경되었는지에 상관없이 트랜잭션 종료시점에 버전값 증가 처리를 함 

    오프라인 선점 잠금

    • 엄격하게 데이터 충돌을 막고 싶다면 누군가 수정중일 때 수정 화면 자체를 실행하지 못하게 해야함 
    • 오프라인 선점 잠금 : 여러 트랜잭션에 걸쳐 동시 변경을 막는다. 

    • 오프라인 선점 방식은 잠금 유효시간을 가져야함 

     

    오프라인 선점 잠금을 위한 LockManager 인터페이스와 관련 클래스

    • tryLock() 메서드는 type과 id를 파라미터로 가짐 
    • 잠금에 성공하면 LockId를 리턴 

     

    DB를 이용한 LockManager구현

    • 잠금 정보 저장 테이블 

    728x90
    반응형