並發策略
在 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();