2015-12-17 36 views
0

我有一個無狀態的ejb bean,有一個entitymanager(em)和這個函數。在什麼情況下會發生這種奇怪的jpa行爲?

public void what(Long commentId) { 
    Comment c = em.find(Comment.class, commentId); 
    em.refresh(c); 
    CommentUpdate cu = new CommentUpdate(c, "new Text"); 
    em.persist(cu); 
    c.getUpdates().add(0, cu); 
    int i = c.getUpdates().size(); 
    em.flush(); 
    int j = c.getUpdates().size(); 
    if (i != j) 
     System.err.println("What?"); 
} 

CommentUpdate是一個非常簡單的實體類。

@Entity 
@NoArgsConstructor(access = AccessLevel.PROTECTED) 
public class CommentUpdate extends AbstractEntity { 

@ManyToOne 
@Getter 
@Setter 
private Comment comment; 

@Getter 
@Setter 
private String text; 

public CommentUpdate(Comment comment, String text) { 
    this.comment = comment; 
    this.text = text; 
} 
} 

評論是稍微複雜一些,但已經像這樣定義的關係:

@OneToMany(mappedBy = "comment") 
@OrderBy("createdAt DESC") 
@Getter 
private List<CommentUpdate> updates = new ArrayList<>(); 

的事情是現在,有時「什麼?」被打印到日誌中。 刷新後新創建的CommentUpdate消失。但又回到了下一次刷新。 這是一個更大的vaadin項目中的方法,我還沒有能夠在一個小型/簡單的項目中重現這一點。有沒有這種情況,這是合乎邏輯的行爲,或者這可能是Glassfish(4.1.1)使用的eclipselink(2.6)中的錯誤?

回答

0

首先懷疑的是,你有一個雙向關係CommentCommentUpdate

@OneToMany(mappedBy = "comment") 
private List<CommentUpdate> updates = new ArrayList<>(); 

,但之間要設置只是其中的一面:

c.getUpdates().add(0, cu); 

對於雙向關係中,你必須設置兩個參考你自己,即。

c.getUpdates().add(0, cu); 
cu.setComment(c); 

不這樣做會導致狀態不一致,就像剛剛遇到的那樣。

JPA specs(章2.9實體關係)說:

的關係的持有端確定更新在數據庫中的關係,如在部分3.2.4中描述

的一對多/多對一雙向關係的許多方面必須是擁有方

並且在部分3 .2.4與數據庫同步

管理實體之間的雙向關係將基於關係擁有方所持有的引用持久化。開發人員有責任保持內存中的引用保持在持有者一方,而保留在內存中的引用在更改時保持一致。

確保對關係的反面進行更改會導致擁有方的適當更新尤爲重要,以確保在同步到數據庫時不會丟失更改。

通常情況下,如果您密切關注JPA規範,那麼EM確實會將所有內容整理出來。但是如果你犯了一個小錯誤,事情會變得怪異。因此,底線是:在commentUpdate對象中設置comment,這是此關係中的主體。

NB:調用

Comment c = em.find(Comment.class, commentId); 

後應該沒有需要刷新c,因爲它只是被取出,並進行管理。

+0

謝謝您的回答啓用緩存。我在CommentUpdate類的cunstructor中設置關係的擁有方。現在我認爲它與一個@preUpdate方法和另一個與CascadeType.REFRESH的關係有關。如果我能瞭解更多,我會自己回答這個問題。 – raffael

+0

然後,你應該首先設置關係的雙方,然後才調用'persist(cu)'。無論如何,張貼更多的上下文可以幫助 - CommentUpdate的代碼,任何'@ PreUpdate','@ PostPersist'等方法。 –

0

可能導致出現此類結果的最可能原因是啓用了緩存,並且您爲髒讀取設置了數據源,從而允許讀取未被更新的更新。使用緩存時,EntityManager將緩存查詢以提高性能。在這種情況下,當你讀取一個關係時,它將從緩存集中讀取它,並且不會查詢表格。更新實體出現在對該方法的第二次調用中的原因是因爲CommentUpdate已經提交給數據庫,因此緩存也會更新。

您可以禁用或使用論文的屬性,如果你正在使用的EclipseLink爲您提供

<property name="eclipselink.query-results-cache" value="false"/> 
<property name="eclipselink.cache.shared.default" value="false"/> 
<property name="eclipselink.cache.size.default" value="0"/> 
<property name="eclipselink.cache.type.default" value="None"/> 
相關問題