2011-01-06 3 views
0

Glassfish 컨테이너에서 JPA를 사용하고 있습니다. 다음 모델이 있습니다 (완료되지 않음)JPA 컬렉션으로 엔티티를 업데이트하는 최상의 방법

@Entity 
public class Node { 
    @Id 
    private String serial; 
    @Version 
    @Column(updatable=false) 
    protected Integer version; 
    private String name; 
    @ManyToMany(cascade = {CascadeType.PERSIST,CascadeType.MERGE}) 
    private Set<LUN> luns = new HashSet<LUN>(); 

@Entity 
public class LUN { 
    @Id 
    private String wwid; 
    @Version 
    @Column(updatable=false) 
    protected Integer version; 
    private String vendor; 
    private String model; 
    private Long capacity; 
    @ManyToMany(mappedBy = "luns") 
    private Set<Node> nodes = new HashSet<Node>(); 

이 정보는 매일 업데이트됩니다. 이제 내 질문은이 일을 수행하는 가장 좋은 방법이 무엇인가하는 것입니다.

필자의 첫 번째 접근 방식은 클라이언트 (LUN)가있는 노드 객체를 매일 생성하고 데이터베이스 (JPA가 작업을 수행하게하고 싶었습니다)를 서비스를 통해 병합합니다.

이제 LUN이없는 테스트를 수행했습니다.

public void updateNode(Node node) { 
    if (!nodeInDB(node)) { 
     LOGGER.log(Level.INFO, "persisting node {0} the first time", node.toString()); 
     em.persist(node); 
    } else { 
     LOGGER.log(Level.INFO, "merging node {0}", node.toString()); 
     node = em.merge(node); 
    } 
} 

테스트 :

@Test 
public void addTest() throws Exception { 
    Node node = new Node(); 
    node.setName("hostname"); 
    node.setSerial("serial"); 
    nodeManager.updateNode(node); 
    nodeManager.updateNode(node); 
    node.setName("newhostname"); 
    nodeManager.updateNode(node); 
} 

이는 @Version 필드없이 작동 나는 무 EJB에서 다음과 같은 서비스가있다. @Version 필드를 사용하면 OptimisticLockException이 발생합니다.

그 방법이 잘못 되었습니까? 항상 em.find (...)를 수행하고 getter 및 setter를 통해 관리되는 엔터티를 수정해야합니까?

도움을 주시면 감사하겠습니다.

BR 르네

답변

1

@version 주석이 낙관적 잠금을 사용하도록 설정하는 데 사용됩니다.

낙관적 잠금을 사용하면 테이블에 성공적으로 기록 할 때마다 버전 카운터가 올라가며, 버전 카운터는 엔티티를 유지할 때마다 읽고 비교됩니다. 쓰기 타임에 엔티티가 테이블의 버전과 처음으로 일치하는 것을 발견했을 때 읽은 버전이 있으면 예외가 발생합니다.

프로그램은 버전 열을 한 번만 읽은 후 테이블을 여러 번 업데이트합니다. 따라서 두 번째로 persist() 또는 merge()를 호출하면 버전 번호가 일치하지 않고 쿼리가 실패합니다. 이는 낙관적 잠금을 사용할 때 예상되는 동작입니다. 처음 읽은 이후로 변경된 행을 덮어 쓰려고했습니다.

마지막 질문에 답하는 방법 : 데이터베이스에 쓸 때마다 변경된 버전 정보를 읽어야합니다. em.refresh()를 호출하여이 작업을 수행 할 수 있습니다.

그러나 전략을 다시 생각해보십시오. 사용자가 변경 사항을 수행하는 동안 데이터 일관성을 보장하기 위해 낙관적 잠금은 트랜잭션에 가장 적합합니다. 일반적으로 데이터를 읽고 사용자에게 표시 한 다음 변경 사항을 기다린 다음 사용자가 작업을 마친 후 데이터를 유지합니다. 트랜잭션이 이러한 쓰기 호출 모두에서 낙관적 인 잠금으로 인해 실패 할 수 있기 때문에이 컨텍스트에서 동일한 데이터 행을 여러 번 쓰고 싶지도 않으며 작성할 필요가 없습니다. 더 간단하게 만드는 것이 아니라 복잡하게 만듭니다.

+0

나는 그것을 이해하지 못한다. 나는 어떤 luns도 아직 추가하지 않았다. – reen

+0

죄송합니다. 분명히 충분히 자세히 읽지 않았습니다. 나는 당신을 위해 나의 대답을 바꾸었다. – weltraumpirat

+0

답변 해 주셔서 대단히 감사합니다. 따라서 해당 시나리오에서 버전 관리를 제거하라는 메시지가 나타납니다. 그런 다음 클라이언트 소프트웨어는 한 번에 하나의 노드 만 업데이트된다는 것을 보장해야합니다. – reen

관련 문제