2013-04-21 1 views
4

사용자 ID가 @ID이고 상위 엔티티 그룹이없는 JPA 엔티티 클래스 사용자가 있습니다. 두 개의 병렬 트랜잭션이 지속될 때 사용자가 동일한 사용자 이름을 사용하는 경우 하나만 커밋되고 다른 하나는 롤백되도록해야합니다.낙관적 잠금 (Google App Engine Java/JPA)을 사용하여 새로운 Datastore 엔티티 생성

예 : 트랜잭션이 시작되면

", 앱 엔진 마지막 업데이트 시간을 확인하여 낙관적 동시성 제어를 사용

User bob = new User("bob"); 
EntityTransaction transaction = em.getTransaction(); 

try { 
    transaction.begin(); 
    User u = em.find(User.class, bob.id()); 
    if (u == null) { 
    em.persist(bob); 
    } else { 
    // identical user already existed before the transaction 
    throw new UserExistsException(); 
    } 
    transaction.commit(); 
} catch (RollbackException e) { 
    // identical user was created during the transaction 
    throw new UserExistsException(); 
} 

는 데이터 저장소의 문서에 따르면, 거래는 낙관적 잠금 방식에 따라 엔티티 그룹에 대한 트랜잭션을 커밋 할 때 App Engine은 트랜잭션에 사용 된 엔티티 그룹의 마지막 업데이트 시간을 다시 확인합니다. 초기 체크 이후 변경된 경우 App Engine은 예외를 throw합니다. " 새로운 (루트) 엔티티를 지속 할 때 (https://developers.google.com/appengine/docs/java/datastore/transactions)

이 작품은, 어떤 트랜잭션 이전에 존재하지 않았던 것인가? 필자의 경우 App Engine은 다른 트랜잭션이 동일한 ID를 가진 사용자를 지속시키는 지 확인합니다. 그렇다면 명시 적으로 @Version 필드가 필요합니까?

+0

로우 레벨 API가 다음과 같이 처리 할 것이라고 주장한 [이 토론 게시판] (https://groups.google.com/d/msg/google-appengine-java/mYKJ-FP1pog/FwC5jtlGBMUJ)을 방금 보았습니다. 이 경우 ConcurrentModificationException 누구나 JPA/JDO에 이상적으로 확인할 수 있습니까? –

+0

게시 한 후 질문을 찾았습니다. http://stackoverflow.com/questions/27370112/google-app-engine-with-jpa-data-racing 직접 해결 했습니까? – jchristof

답변

1

문제에 대한 긴 기한 마감 시간을 넣으려면 : 대답은 "예"이고 위의 코드는 예상대로 작동해야합니다. 간단히 말해 낙관적 동시성 제어 메커니즘은 (루트) 엔티티의 종류 "사용자"와 주어진 식별자 "밥"을 사용하여 두 트랜잭션에서 사용 된 (새로운) 엔티티 그룹을 비교합니다. Datastore docs 명시 적으로 지금 창조 사건을 해결 :

을 두 개 이상의 트랜잭션이 (중 기존의 엔티티 를 업데이트하거나 새로운 만들기), 첫 번째 트랜잭션이 커밋하는 동시에 같은 엔티티 그룹을 변경하려고 할 때 성공하고 다른 모든 사람들은 실패 할 것입니다.

JPA를 사용하면이 경우 RollbackException이 발생합니다. 하위 레벨 API는 ConcurrentModificationException을 발생시킵니다. Objectify를 사용하고 있다면 (내가 강력히 권장하는) 실패한 트랜잭션은 자동으로 재 시도됩니다. 따라서 거래 내에서 두 번째 시도에서 덮어 쓰지 않는 한 엔티티가 존재하는지 먼저 확인해야합니다.

관련 문제