永遠不要編寫緩存解決方案

另一種加快數據庫工作的方法是緩存我們之前已經請求過的對象。

重要的!永遠不要編寫自己的緩存解決方案。這項任務有很多你做夢也想不到的陷阱。

問題 1 -緩存刷新。有時,當需要從緩存中刪除對像或在緩存中更新對象時,會發生事件。勝任地做到這一點的唯一方法是通過緩存引擎將所有請求傳遞給數據庫。否則,每次你都必須明確地告訴緩存應該刪除或更新其中的哪些對象。

問題 2 -內存不足。在您發現內存中的對象佔用大量空間之前,緩存似乎是個好主意。您需要額外的數十 GB 內存才能使服務器應用程序緩存有效工作。

由於內存總是不足,因此需要一種從緩存中刪除對象的有效策略。這有點類似於Java中的垃圾收集器。你還記得,幾十年來,最聰明的人一直在發明各種按代標記對象的方法,等等。

問題 3 -不同的策略。正如實踐所示,在緩存中存儲和更新的不同策略對不同的對像有效。高效的緩存系統不能對所有對像只執行一種策略。

問題 4 -的高效存儲。您不能只將對象存儲在緩存中。對象經常包含對其他對象的引用,等等。以這種速度,您將不需要垃圾收集器:它只是沒有任何東西可以刪除。

因此,與其存儲對象本身,不如存儲它們的原始字段的值有時更有效。以及基於它們快速構建對象的系統。

結果,您將在內存中獲得一個完整的虛擬 DBMS,它應該可以快速運行並且消耗很少的內存。

數據庫緩存

除了直接在 Java 程序中緩存外,緩存通常直接在數據庫中組織。

有四大方法:

第一種方法是對數據庫進行非規範化。SQL Server 在內存中存儲數據的方式與在表中的存儲方式不同。

當數據以表的形式存儲在磁盤上時,開發人員通常會盡量避免數據重複——這個過程稱為數據庫規範化。因此,為了加快內存中數據的處理速度,執行了相反的過程——數據庫反規範化。一堆相關的表已經可以以組合的形式存儲——以大表的形式等。

第二種方法是查詢緩存。並查詢結果。

DBMS 經常看到相同或相似的請求。然後它只是開始緩存這些請求及其響應。但與此同時,您需要確保及時從緩存中刪除數據庫中已更改的行。

對於可以分析查詢並幫助 DBMS 確定如何最好地緩存它們的人來說,這種方法可能非常有效。

第三種方法是內存數據庫

另一種常用的方法。另一個數據庫位於服務器和 DBMS 之間,它將所有數據僅存儲在內存中。它也稱為 In-Memory-DB。如果您有許多不同的服務器訪問同一個數據庫,那麼使用 In-Memory-DB 您可以根據特定服務器的類型組織緩存。

例子:

方法4——數據庫集群。幾個只讀基地。

另一種解決方案是使用集群:多個相同類型的 DBMS 包含相同的數據。同時,您可以從所有數據庫讀取數據,只寫入一個。然後與其餘數據庫同步。

這是一個非常好的解決方案,因為它易於配置並且在實踐中有效。通常,對數據庫的一個更改數據請求,會收到 10-100 個讀取數據的請求。

Hibernate 中的緩存類型

Hibernate 支持三種級別的緩存:

  • 會話級緩存(Session)
  • 在 SessionFactory 級別緩存
  • 緩存請求(及其結果)

你可以嘗試用這樣一個圖的形式來表示這個系統:

最簡單的緩存類型(也稱為一級緩存)是在 Hibernate 會話級別實現的。默認情況下,Hibernate 總是使用這個緩存並且不能被禁用

讓我們立即考慮以下示例:

Employee director1 = session.get(Employee.class, 4);
Employee director2 = session.get(Employee.class, 4);

assertTrue(director1 == director2);

看起來這裡會執行對數據庫的兩個查詢,但事實並非如此。在第一次請求數據庫後,Employee 對象將被緩存。而如果在同一個會話中再次查詢該對象,Hibernate 將返回同一個 Java 對象。

相同的對象意味著即使是對象引用也是相同的。這真的是同一個對象。

save()update()saveOrUpdate()load()get()list()iterate()scroll()方法將始終使用一級緩存。其實,沒有什麼可以補充的了。

二級緩存

如果一級緩存綁定了session對象,那麼二級緩存就綁定了session對象。會話工廠. 這意味著對像在這個緩存中的可見性比在一級緩存中要寬得多。

例子:

Session session = factory.openSession();
Employee director1 = session.get(Employee.class, 4);
session.close();

Session session = factory.openSession();
Employee director2 = session.get(Employee.class, 4);
session.close();

assertTrue(director1 != director2);
assertTrue(director1.equals(director2));

在此示例中,將對數據庫進行兩次查詢。Hibernate 將返回相同的對象,但它不會是同一個對象——它們將有不同的引用。

二級緩存默認是禁用的。因此,我們對數據庫有兩個查詢而不是一個。

要啟用它,您需要在 hibernate.cfg.xml 文件中寫入以下行:

<property name="hibernate.cache.provider_class" value="net.sf.ehcache.hibernate.SingletEhCacheProvider"/>
<property name="hibernate.cache.use_second_level_cache" value="true"/>

啟用二級緩存後,Hibernate 的行為會發生一些變化:

Session session = factory.openSession();
Employee director1 = session.get(Employee.class, 4);
session.close();

Session session = factory.openSession();
Employee director2 = session.get(Employee.class, 4);
session.close();

assertTrue(director1 == director2);

只有在所有這些操作之後才會啟用二級緩存,並且在上面的示例中,只會執行一次對數據庫的查詢。