簡體   English   中英

JPA / Hibernate實體類和同步的最佳實踐是什么?

[英]What is the best practice for JPA/Hibernate entity classes and synchronization?

似乎我所見過的大多數JPA / Hibernate實體Bean類示例都沒有顯式同步。 但是,可以在建立事務的上下文中調用這些對象的getter / setter。 而且有可能在多個線程中調用這些方法(盡管這可能是異常且怪異的)。

似乎如果跨多個線程構建了對象,那么可能會丟失對對象狀態的更改,這將是令人遺憾的。

那么,是否遺漏了同步的最佳實踐? Hibernate插樁代碼是否為我做好了適當的同步?

舉個例子:

@Entity
public class Ninja {
  @Id @GeneratedValue
  private Long id;

  @Column 
  private String name;

  @Column
  private int throwingStars;

  public Ninja() {}
  public int getThrowingStars() { return throwingStars; } 
  public void addThrowingStar() { throwingStars += 1; }
}

拋星方法需要同步嗎? 我當然不希望我的忍者失去任何投擲的星星。

我認為您永遠不要跨線程共享域對象。 實際上,由於必須保護此類數據,因此我通常在線程之間很少共享。 我已經構建了一些大型/高性能系統,並且從未違反過此規則。 如果您需要並行化工作,則可以這樣做,但不必共享域對象的實例。 每個線程應從數據庫讀取數據,通過更改/創建對象對其進行操作,然后提交/回滾事務。 工作輸入/輸出通常應該是值/只讀對象。

“而且有可能在多個線程中調用這些方法(盡管這可能是異常和怪異的)。”

因為我對JPA的經驗不足,所以我只能代表休眠。 您調用的對象並不總是與調用get的對象相同。 當Hibernate為您加載對象時,它會調用set *方法,然后您(和您的線程)將剩下的時間用於調用。

同樣,當您(即您的編寫器線程)修改現有對象然后再次保存時,您需要保護對對象的訪問(以便其他讀取器/編寫器線程不會讀取臟數據)。

這兩個線程的對象可能不相同。 假設您的線程使用會話工廠訪問數據庫,那么從會話中獲取的對象應被視為“獨立”(我相信休眠狀態會為每個get()創建“新”對象,除非它們在會話中)。

至於您的星星問題,當兩個人從數據庫中獲取同一行時,這是相同的,數據庫的“ ACID”屬性將確保每個操作都是原子的,因此如果您從線程t1中的忍者中刪除星星並進行提交 ,線程t2將讀取t1的提交值。

另外,您可以要求休眠狀態將相關忍者的行鎖定在T1中,這樣,即使T2請求該行,它也必須等待,直到T1提交或中止。

JPA /休眠實體是POJO。 Hibernate和任何JPA-Provider都不會更改運行時語義。

因此,如果您在使用簡單的POJO時遇到並發問題,那么您的實體也會遇到這些問題!

在所有我看到的系統中,域模型不是threadave,實體實例不能被多個線程訪問。

但是,您可以同時具有同一實體的多個實例。 在這種情況下,同步是通過數據庫完成的。 這里的模式是樂觀鎖定和悲觀鎖定。 Hibernate和JPA可以幫助您實現這些模式。

解決問題的最佳實踐是樂觀鎖定:

根據Java Persistence API(JPA)規范(第3.4.1章):

樂觀鎖定是一種技術,用於確保僅在自從讀取實體狀態以來沒有中間事務更新實體狀態的數據時,才對與實體狀態相對應的數據庫數據進行更新。 這樣可確保對該數據的更新或刪除與數據庫的當前狀態一致,並且不會丟失中間的更新。

您需要在類中添加@Version批注,並在數據庫表中添加一列。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM