DDD와의 트랜잭션 일관성 보장


9

저는 DDD로 시작하여 국가 간 일관성을 보장하기 위해 집계 루트가 사용됨을 이해합니다. 하나의 응용 프로그램 서비스에서 여러 집계를 수정해서는 안됩니다.

그러나 다음 상황을 처리하는 방법을 알고 싶습니다.

Products라는 집계 루트가 있습니다.

Group이라는 집계 루트도 있습니다.

둘 다 ID가 있으며 독립적으로 편집 할 수 있습니다.

여러 제품이 같은 그룹을 가리킬 수 있습니다.

제품 그룹을 변경할 수있는 응용 프로그램 서비스가 있습니다.

ProductService.ChangeProductGroup(string productId, string groupId)

  1. 검사 그룹 존재
  2. 리포지토리에서 제품 가져 오기
  3. 그룹 설정
  4. 제품을 다시 저장소에 씁니다.

그룹을 삭제할 수있는 응용 프로그램 서비스도 있습니다.

GroupService.DeleteGroup(string groupId) 1. groupId가 제공된 groupId로 설정된 리포지토리에서 제품을 가져오고 개수가 0 또는 중단되었는지 확인합니다. 2. 그룹 리포지토리에서 그룹을 삭제합니다. 3. 변경 내용을 저장합니다.

내 질문은 다음과 같은 시나리오입니다.

ProductService.ChangeProductGroup에서 그룹이 존재하는지 확인한 다음 (이것이 있는지)이 확인 직후에 별도의 사용자가 다른 GroupService.DeleteGroup을 통해 productGroup을 삭제합니다. 이 경우 방금 삭제 한 제품에 대한 참조를 설정 했습니까?

다른 도메인 디자인을 사용해야하거나 (필요한 경우 추가 요소 추가) 트랜잭션을 사용해야한다는 점에서 이것이 디자인의 결함입니까?

답변:


2

우리는 같은 문제가 있습니다.

그리고이 문제를 해결할 방법이 없지만 최악의 경우 예외를 얻기 위해 DB에서 트랜잭션이나 일관성 검사를 사용합니다.

비즈니스 트랜잭션이 완료 될 때까지 직렬화 가능한 트랜잭션과 어느 정도 일치 할 때까지 비관적 잠금을 사용하여 다른 클라이언트의 집계 루트 또는 해당 부분 만 차단할 수 있습니다.

당신이가는 길은 시스템과 비즈니스 로직에 달려 있습니다.
동시성은 결코 쉬운 일이 아닙니다.
문제를 발견하더라도 어떻게 해결할 수 있습니까? 작업을 취소하거나 사용자가 변경 사항을 '병합'하도록 허용 하시겠습니까?

우리는 기본적으로 Entity Framework를 사용하고 EF6은 기본적으로 read_commited_snapshot을 사용하므로 저장소에서 두 번 연속 읽기를 수행하면 데이터가 일치하지 않을 수 있습니다. 비즈니스 프로세스를보다 명확하게 설명하고 정보를 바탕으로 한 결정을 내릴 수있는 미래를 염두에 두십시오. 그렇습니다. 우리는 여전히 모델 수준에서 일관성을 검사합니다. 최소한 DB와 별도로 BL을 테스트 할 수 있습니다.

또한 '긴'비즈니스 트랜잭션이있는 경우 저장소 일관성 에 대해 생각하는 것이 좋습니다 . 그것이 밝혀 졌을 때 꽤 까다 롭습니다.


1

이것은 도메인 기반 디자인 관련 질문이 아니라 리소스 관리 질문이라고 생각합니다.

자원 은 획득 할 때 잠겨 있어야합니다 .

이는 애플리케이션 서비스가 획득 한 자원 ( Group예 : 집합)이 수정 될 것임을 미리 알고있는 경우에 해당됩니다 . 도메인 기반 디자인에서 리소스 잠금은 리포지토리에 속하는 측면입니다.


잠금은 "필수"가 아닙니다. 실제로 장기 실행 트랜잭션과 관련하여 매우 끔찍한 일입니다. 모든 최신 ORM이 즉시 지원하는 낙관적 동시성을 사용하는 것이 좋습니다. 낙관적 동시성에 대한 가장 큰 장점은 원자 업데이트를 지원하는 한 비 트랜잭션 데이터베이스에서도 작동한다는 것입니다.
Aaronaught

1
장기 실행 트랜잭션 내에서 잠금의 단점에 동의하지만 @ g18c에 설명 된 시나리오는 그 반대의 즉, 개별 집계에 대한 간단한 작업을 암시합니다.
rucamzu

0

그룹 엔티티에 제품 ID를 저장하지 않는 이유는 무엇입니까? 이런 식으로 당신은 일을 더 쉽게 만들어 줄 단일 집합체 만 다룰 것입니다.

그런 다음 일부 유형의 동시성 패턴을 구현해야합니다.

그룹에 제품 추가

  1. 제품이 존재하는지 확인
  2. 저장소에서 그룹 가져 오기 (버전 ID 특성 포함)
  3. Group.Add (ProductId)
  4. 저장소를 사용하여 그룹을 저장하십시오 (새 버전 ID로 업데이트하고 버전이 변경되지 않도록 where 절을 추가하십시오).

많은 ORM에는 버전 ID 또는 타임 스탬프를 사용하여 최적화 된 낙관적 동시성이 있지만 직접 롤링하기는 쉽습니다. 다음은 Nhibernate http://ayende.com/blog/3946/nhibernate-mapping-concurrency 에서 어떻게 수행되었는지에 대한 좋은 게시물입니다 .


0

트랜잭션이 도움이 될 수 있지만 특히 시나리오가 몇 가지 사례로 제한된 경우 다른 방법이 있습니다.

돌연변이를 수행하는 쿼리에 검사를 포함시켜 각 검사 및 돌연변이 쌍을 원 자성 연산으로 효과적으로 만들 수 있습니다.

제품 업데이트 쿼리 내부는 (새로 참조 된) 그룹을 조인합니다. 이로 인해 해당 그룹이 사라지면 아무것도 업데이트되지 않습니다.

그룹 삭제 쿼리는 해당 제품을 가리키는 제품을 조인하며 조인 결과 중 하나의 열이 null이어야한다는 추가 조건이 있습니다. 이로 인해 제품이 가리키는 경우 아무것도 삭제되지 않습니다.

쿼리는 일치하거나 업데이트 된 행 수를 반환합니다. 결과가 0이면 경쟁 조건을 잃고 아무 것도하지 않은 것입니다. 예외를 던질 수 있으며 응용 프로그램 계층은 처음부터 다시 시도하는 등 원하는 작업을 처리 할 수 ​​있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.