일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 |
- Java8
- 스트림
- Java in action
- Design Pattern
- Was
- Clean Code
- CQRS
- head first
- spring
- Template Method Pattern
- 클린코드
- spring boot
- 디자인 패턴
- jsp
- AWS101
- web
- 자바의 신
- domain
- 자바8
- 자바8인액션
- Java
- 패스트캠퍼스
- SERVLET
- spring Batch
- facade pattern
- 자바
- ddd
- Java 8 in action
- Java8 in action
- Stream
- Today
- Total
주난v 개발 성장기
[DDD START!] 8장. 애그리거트 트랜잭션 관리 본문
애그리거트와 트랜잭션
운영자 스레드와 고객 스레드는 개념적으로 동일한 애그리거트지만, 물리적으로는 다른 애그릭더트 객체 이다.
운영자 스레드가 주문 애그리거트 객체의 배송 상태를 변경했는데, 고객이 그 사이에 배송지 정보를 변경
--> 애그리거트의 일관성이 깨진다.
이를 보완하는 트랜잭션 처리 기법이 필요!
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 구현
'개발 성장기 > DDD' 카테고리의 다른 글
[DDD START!] 10장. 이벤트 (0) | 2020.06.09 |
---|---|
[DDD START!] 9장. 도메인 모델과 BOUNDED CONTEXT (0) | 2020.06.08 |
[DDD START!] 7장 도메인 서비스 (0) | 2020.05.29 |
[DDD START!] 6장. 응용 서비스와 표현 영역 (1) | 2020.05.26 |
[DDD START!] 5장. 리포지터리의 조회 기능 (0) | 2020.05.22 |