2012-11-02 5 views
3

JPA & Hibernate를 사용하여 낙관적 동시성 제어에 @Version을 사용하고 싶습니다.Hibernate/JPA 버전 동시성 제어 및 DTO/변경 명령 ​​패턴

두 병렬 트랜잭션의 일반적인 시나리오에서 어떻게 작동하는지 알고 있습니다. 폼과 엔터티간에 1 : 1 매핑을 사용하는 CRUD가있는 경우 version을 숨겨진 필드로 전달하여 사용자가 동시 수정을 방지 할 수 있음을 알고 있습니다.

DTO 또는 변경 명령 ​​패턴을 사용하는보다 흥미로운 사례는 무엇입니까? 이 시나리오에서도 @Version을 사용할 수 있습니까?

예를 들어 설명해 드리겠습니다.

@Entity 
public class MyEntity { 
    @Id private int id; 
    @Version private int version; 
    private String someField; 
    private String someOtherField; 
    // ... 
} 

지금 (안 동시에, 그래서 거래는 중복되지 않음)의이 두 사용자가 이것에 대한 GUI를 열 말을 일부 수정하고 변경 사항을 저장 할 수 있습니다. 나는 주위에 전체 개체를 전달하는 경우

, 두 번째 트랜잭션이 실패합니다

좋은,하지만, 변경 명령 ​​등의 DTO를 사용하는 것이 때로는 사방 개체를 전달하는 아이디어를 좋아하고하지 않는
@Transactional 
public void updateMyEntity(MyEntity newState) { 
    entityManager.merge(newState); 
} 

단순 변경 명령에 대한

은 결국 일부 서비스를 다음과 같이 호출에 사용되는 맵입니다 : 분명히

@Transactional 
public void updateMyEntity(int entityId, int version, Map<String, Object> changes) { 
    MyEntity instance = loadEntity(entityId); 
    for(String field : changes.keySey()) { 
     setWithReflection(instance, field, changes.get(field)); 
    } 
    // version is unused - can I use it somehow? 
} 

, 두 사용자가 내 GUI를 열 경우, 두 변경을 한 다음에 하나씩 실행하십시오.이 경우 두 변경 사항이 적용되고 마지막 변경 사항이 적용됩니다. 나는이 시나리오가 동시에 수정을 감지하고 싶습니다 (두 번째 사용자는 예외를 얻어야합니다).

어떻게하면됩니까?

답변

0

질문을 올바르게 이해하면 private int version 필드에 대한 설정자가 필요하며 엔티티를 업데이트 할 때 엔티티에서 설정해야합니다. 물론 DTO는 항상 버전 데이터를 전송해야합니다. 궁극적으로 다음과 같이 할 수도 있습니다.

MyEntity instance = loadEntity(entityId); 
entityManager.detach(instance); 
for(String field : changes.keySey()) { 
    setWithReflection(instance, field, changes.get(field)); 
} 
//set also the version field, if the loop above does not set it 
entityManager.merge(instance);