2009-08-14 33 views
1

我有兩個實體,如下列:Shound我避免使用mappedBy來保持我的應用程序穩定?

@Entity 
public class Trip { 

    @OneToMany(mappedBy = "trip", fetch = FetchType.LAZY) 
    private Set<Job> jobs = new HashSet<Job>(); 

} 

@Entity 
public class Job { 

    @ManyToOne(fetch = FetchType.LAZY) 
    private Trip trip; 

} 

的問題是關係的mappedBy在不同情況下表現不同。下面是一個例子

EntityManager em1 = unit.createEntityManager(); 
    EntityManager em2 = unit.createEntityManager(); 

    // One EM starts transaction and stores a trip 
    em1.getTransaction().begin(); 

    Trip trip = new Trip(); 
    em1.persist(trip); 

    Long tripId = trip.getId(); 

    assertThat(tripId).isPositive(); 

    em1.getTransaction().commit(); 

    // Then em2 starts different transaction 
    em2.getTransaction().begin(); 

    // Looking up for the trip through clean em (cache is empty) 
    Trip em2Trip = em2.find(Trip.class, tripId); 

    Job job = new Job(); 
    job.setTrip(em2Trip); 

    em2.persist(job); 

    // The em2Trip should not be updated 

    assertThat(em2Trip.getJobs()).hasSize(1); 

    em2.getTransaction().commit(); 

    em1.getTransaction().begin(); 

    Trip em1Trip = em1.find(Trip.class, tripId); 

    // fails here 
    assertThat(em1Trip.getJobs()).hasSize(1); 

    em1.getTransaction().commit(); 

上面的代碼表明,如果一個實體在實體管理器的緩存已經加載,對於關係的mappedBy吸氣劑返回無效結果。

我有一個證明它不能在JBoss下工作。以下代碼的行爲有所不同,具體取決於正在使用哪個實體管理器。結果是不可預測的。

 Trip trip = em.find(Trip.class, tripId); 
     if (trip.getJobs().size() == 0) ... 

這是否意味着mappedBy會在引入和使用後自動生成應用程序錯誤?

P.S.我不想濫用冬眠。我只想知道是否有人遇到了這樣的問題,他們是如何應對的?

+0

請編輯您的問題,並儘量保持客觀。沒有人喜歡讀咆哮。 – 2009-08-14 13:31:38

+0

現在好點了嗎? – artemb 2009-08-14 14:04:59

回答

2

你正在描述的行爲有絕對沒有做與協會;如果您只是嘗試從兩個實體管理器讀取/更新簡單的POJO,則會得到完全相同的結果。一旦你的實體與持久性上下文相關聯,它就不會自動從數據庫中刷新。這是一種記錄的行爲 - 在絕大多數情況下,這是一種DESIRED行爲。

至於「讓你的應用程序穩定」雲:

  1. EntityManager實例直接對應到Hibernate會話,因此不應當保持較長時間。如果您重寫上面的代碼以使用新的EntityManager實例(em3)而不是重複使用em1,則問題將消失。
  2. EntityManager有一個refresh()方法,您可以調用它來從數據庫重新加載實體狀態。
  3. EntityManager有一個clear()方法,它將徹底清除持久性上下文,從而也可以防止此問題。儘管謹慎謹慎地使用它,但調用clear()而不使用flush()將丟棄所有未完成的更新。
+0

沒錯,簡單的屬性也不會更新!感謝您指出了這一點。 – artemb 2009-08-18 12:12:42

1

使用mappedBy(即雙向關聯)不是錯誤的或不一致的。但是配置起來很麻煩,你必須非常小心如何使用它 - 這不是一個神奇的項目符號,如果你不遵循編程指南,你可能會讓你的實體處於不一致的狀態。

我傾向於避免他們出於這個原因;我只用它們,如果我真的需要雙向關聯,以我的經驗,這是非常罕見的。

+1

優秀的答案,以及一個令人耳目一新的變化,以查看雙向的建議。 Hibernate引用使用了太多的argument-by-assertion。 – 2012-10-17 18:27:15

相關問題