주난v 개발 성장기

[DDD START!] 8장. 애그리거트 트랜잭션 관리 본문

개발 성장기/DDD

[DDD START!] 8장. 애그리거트 트랜잭션 관리

주난v 2020. 6. 2. 07:31

애그리거트와 트랜잭션

 

운영자 스레드와 고객 스레드는 개념적으로 동일한 애그리거트지만, 물리적으로는 다른 애그릭더트 객체 이다.

운영자 스레드가 주문 애그리거트 객체의 배송 상태를 변경했는데, 고객이 그 사이에 배송지 정보를 변경

--> 애그리거트의 일관성이 깨진다. 

 

 

이를 보완하는 트랜잭션 처리 기법이 필요!

 

1. 선점(Pessimistic) 잠금

- 먼저 애그리거트를 구한 스레드가 사용이 끝날 때까지 다른 스레드가 해당 애그리거트를 수정하는 것을 막는다.

 

한 스레드가 애그리거트를 구하고 수정하는 동안 다른 스레드가 수정할 수 없으므로, 동시에 데이터를 수정하는 충돌 문제 해결 가능

 

선점 잠금 방식은 DBMS가 제공하는 행 단위 잠금을 사용해서 구현한다.

LockModeType.PESIMISTIC_WRITE 사용(Hibernate에서는 for update 쿼리를 이용해서 구현한다.)

 

Order order = entityManger.find(Order.class, orderNo, LockModeType.PESSIMISTIC_WRITE);

 

한 스레드가 먼저 선점한 잠금을 다른 스레드에서 구할 수 없어 더 이상 다음 단계를 진행하지 못하는 교착 상태에 빠지게 된다.

따라서, 최대 대기 시간 설정 필요

 

Map<String, Object> hints = new HashMap<>)();

hints.put("javax.persistence.lock.timeout", 2000);

Order order = entityManger.find(Order.class, orderNo, LockModeType.PESSIMISTIC_WRITE, hints);

 

2. 비선점(Optimistic) 잠금

 

동시에 접근하는 것을 막는 대신 변경한 데이터를 실제 DBMS에 반영하는 시점에 변경 가능 여부를 확인한다. (version)

- 수정할 애그리거트와 매핑되는 테이블의 버전 값이 현재 애그리거트와 동일한 경우에만 데이터를 수정한다.

- 수정에 성공하면 버전 값을 1 증가 시킨다. 따라서, 다른 트랜잭션이 먼저 데이터를 수정해서 버전 값이 바뀌면 데이터 수정에 실패한다.

 

JPA는 버전을 이용한 비선점 잠금 기능을 지원

@Version

비선점 잠금 쿼리 실행 시 결과로 수정된 해으이 개수가 0이면, 이미 누군가 수정한 것이고, 트랜잭션이 충돌한 것이다.

- 트랜잭션 종료 시점에 Exception  발생

- @Transactional

- OptimisticLockingFailureException 발생

 

비선점 잠금 방식을 여러 트랜잭션으로 확장하려면, 뷰로 보여줄 때 버전 정보도 hidden으로 폼 전송시에 서버에 함께 전달되도록 한다.

 

if (!order.matchVersion(req.getVersion() {

      throw new VersionConflictException(); // 이를 이용해서 표현 계층에 알릴 수 있다.

}

 

Exception의 종류 2개

1. 스프링에서 제공 - OptimisticLockingFailureException : 동시에 애그리거트를 수정했다는 것을 의미

2. 응용 서비스 코드에서 발생 - VersionConflictException : 이미 누군가가 애그리거트를 수정했다는 것을 의미

 

강제 버전 증가

- 애그리거트 루트가 아닌 다른 엔티티만 변경되었을 경우, 루트 엔티티의 버전 값은 갱신되지 않는다.

하지만, 일부 값이 바뀌면 논리적으로 애그리거트는 바뀐 것이다.

--> 따라서, 비선점 잠금이 올바르게 동작해야한다.

 

Order order = entityManger.find(Order.class, orderNo, LockModeType.OPTIMISTIC_FORCE_INCREMENT);

//트랜잭션 시점에 무조건 버전 값 증가 처리를 한다.

 

요약

선점 잠금 방식 - 한 트랜잭션 범위에서만 적용

비선점 잠금 방식 - 나중에 버전 충돌을 확인

오프라인 선점 기법

여러 트랜잭션에 걸쳐 동시 변경을 막는다.(ex. 위키)

LockManager 인터페이스를 구현한다. (tryLock, checkLock, releaseLock)

 

데이터 수정 폼에 동시에 접근하는 것을 제어할 수 있다.

 

잠금을 선점하는데 실패하면 LockException 발생

-> 다른 사용자가 데이터를 수정 중이니 나중에 다시 시도해 보라는 안내 화면 유도가능

 

DB를 이용한 LockManager 구현