並發策略

在 Hibernate 中啟用二級緩存後,您需要向 Hibernate 說明我們要緩存哪些 Entity 對像以及如何緩存。

為此,Hibernate 為實體類提供了一個特殊的註釋 - @Cache。例子:

@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)

需要為我們要為其使用二級緩存的每個 Entity 實體編寫此註釋。例子:

@Entity
@Table(name = "employee")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Employee {
    @Id
    private Integer id;
    private Set<Task> tasks;
}

如果從不同線程訪問緩存實體,Hibernate 有 4 種可能的訪問策略:

  • 只讀
  • 讀寫
  • 非嚴格讀寫
  • 事務性的

只讀。一種永不改變的適合數據的並發策略。Hibernate 將簡單地將這些對象存儲在它的內存中。僅將其用作參考數據。

數據庫存儲了大量永遠不會改變的信息。例如,一個表保留了​​一個只添加但從未更改或刪除的事件列表。如果您需要通過 Hibernate 使用此表,那麼只讀緩存策略將適合您。

讀寫(read-write)。對主要可讀的數據使用此策略。然而,Hibernate 將跟踪更改此數據的嘗試,儘管它希望它們很少發生。

您需要主要緩存那些很少更改且經常被讀取/請求的對象。如果你有這樣的對象,那麼你需要對它們使用讀寫策略。

非嚴格讀寫。該策略不保證緩存和數據庫之間的一致性。如果數據幾乎從不更改並且過時數據的小概率不是關鍵問題,請使用此策略。

與讀寫策略不同,此策略假定可變數據未鎖定以供讀取。這可能導致對像在一個地方被更改,而在另一個地方,有人正在閱讀它的舊版本。

例如,某個用戶更改了他的評論,但其他用戶一段時間內仍能看到他的舊版本。如果這對您來說不是問題,則使用非嚴格讀寫策略。

事務性的。將此策略主要用於只讀數據,在極少數更新情況下防止並發事務中的陳舊數據很重要。

將數據存儲在緩存中

您應該記住的關於二級緩存的另一個重要細節是 Hibernate 本身不存儲您的類的對象。它將信息存儲為字符串、數字等的數組。

對象標識符充當指向此信息的指針。從概念上講,這有點像 Map,其中對象的 id 是鍵,數據數組是值。你可以這樣想像:

1 -> { "Ivanov", 1, null , {1,2,5} }
2 -> { "Petrov", 2, null , {1,2,5} }
3 -> { "Sidorov", 3, null , {1,2,5} }

考慮到每個對象佔用多少額外內存,這是非常合理的。

除了上述之外,您還應該記住,默認情況下您的實體類的依賴項也不會被緩存。例如,如果我們考慮上面的類Employee,那麼在獲取時,任務集合將從數據庫中檢索,而不是從二級緩存中檢索

如果您還想緩存依賴項,那麼該類應該如下所示:

@Entity
@Table(name = "employee")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Employee {
    @Id
    private Integer id;

   @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
   private Set<Task> tasks;
}

最後一個細節——只有在一級緩存中找不到所需對象時,才會從二級緩存中讀取。

緩存模式

Hibernate 允許非常靈活的緩存管理。您可以為每個單獨的會話甚至每個數據庫請求設置緩存模式。

有五種這樣的模式:

  • 得到
  • 忽略
  • 普通的
  • 刷新

下表描述了他們的工作:

緩存模式 描述
得到 數據從緩存中讀取但不添加到緩存中。
忽略 會話不與緩存交互。
普通的 從緩存中讀取數據並將其添加到其中。
數據永遠不會從緩存中取出,而是添加到緩存中。
刷新 數據永遠不會從緩存中取出,而是添加到緩存中。在這種模式下,額外使用 hibernate.cache.use_minimal_puts 設置。

為會話設置緩存模式的示例:

session.setCacheMode(CacheMode.GET);
Employee director = session.createQuery("from Employee where id = 4").uniqueResult();

還有一個設置會話和請求模式的示例:

session.setCacheMode(CacheMode.GET);
Query query = session.createQuery("from Employee where id = 4");
query.setCacheMode(CacheMode.IGNORE); // Ignore cache work for this request
Employee director = query.uniqueResult();