為什麼需要查詢緩存

讓我們用 HQL 中的員工重寫我們的例子:

Employee director1 = session.createQuery("from Employee where id = 4").uniqueResult();
Employee director2 = session.createQuery("from Employee where id = 4").uniqueResult();

assertTrue(director1 != director2);

此類查詢的結果不存儲在一級或二級緩存中。

這正是可以使用查詢緩存的地方。它也是默認禁用的。要啟用它,請將以下行添加到配置文件中:

<property name="hibernate.cache.use_query_cache" value="true"/>

但這只是解決方案的一半。我們啟用了查詢緩存,但我們還需要指定要緩存哪些查詢結果。這必須寫在查詢中:

Query query = session.createQuery("from Employee where id = 4");
query.setCacheable(true);
Employee director1 = query.uniqueResult();

查詢緩存類似於二級緩存。但是,與它不同的是,這裡緩存數據的關鍵不是對象標識符,而是查詢參數集。而數據本身就是符合查詢條件的對象的標識。因此,將此緩存與二級緩存一起使用是合理的。

清除緩存

使用緩存時的一項重要任務是確保緩存的對象發生更改並將它們從緩存中刪除(或更新它們)。Hibernate 在這方面做得很好。有時甚至看起來他被“在任何無法理解的情況下清除緩存”的規則所引導。

假設您想通過 HQL 更新用戶數據:

Query query = session.createQuery("update Employee set name=’Alex’ where id = 4")
query. executeUpdate();

Hibernate 無法確切知道數據庫中發生了什麼變化,但它知道您正在更改 Employee 對象。因此,執行此查詢後,Hibernate 將從其緩存中刪除所有 Employee 類型的對象

但 NativeQuery 的工作方式更有趣:

Query nativeQuery = session.createNativeQuery("update employee set name=’Alex’ where id = 4")
nativeQuery.executeUpdate();

已執行對數據庫的本機 SQL 查詢。這意味著數據庫中發生了一些變化——在executeUpdate()方法中調用了請求。因此,在這種情況下,Hibernate 會謹慎行事,並從其緩存中刪除所有類型所有對象

你覺得如何?你調用一個無害的請求,Hibernate 作為響應從緩存中刪除所有數據!這肯定比他保留與底座不同的物體要好,但僅此而已!

因此,Hibernate 的創建者很快想出瞭如何在這種情況下幫助 Hibernate。您可以告訴它要從緩存中刪除哪種實體類型:

Query nativeQuery = session.createNativeQuery("update employee set name=’Alex’ where id = 4");
nativeQuery.unwrap(org.hibernate.SQLQuery.class).addSynchronizedEntityClass(Employee.class);
nativeQuery.executeUpdate();
備註. 本機選擇查詢不會刷新緩存,只會插入、更新、刪除、過程調用等。

手動清除緩存

由於某些原因,您可能想自己從緩存中刪除一個對象。這可以通過不同的方式完成。

注意。緩存中的對象存儲在稱為區域的組中。默認情況下,區域名稱與類名稱相同。因此,如果您有com.codegym.Employee類型的對象,那麼所有這些對像都將存儲在名為“ com.codegym.employee ”的組(區域)中。

如果你想訪問緩存並用它做一些事情,你可以用 SessionFactory 對象和 getCache ()方法來完成:

session.getSessionFactory().getCache().evictQueryRegion("com.codegym.employee”);

如果要從所有組(區域)中刪除數據,則需要運行以下查詢:

session.getSessionFactory().getCache().evictAllRegions();

要從緩存中刪除一個對象,您需要傳遞其名稱(類型)和 ID。您可以通過兩種方式執行此操作:

session.getSessionFactory().getCache().evictEntityData("Employee, 4);

session.getSessionFactory().getCache().evictEntityData(com.codegym.Employee.class, 4);

您還可以檢查特定對像是否在緩存中:

session.getSessionFactory().getCache().containsEntity("Employee, 4);
session.getSessionFactory().getCache().containsEntity(com.codegym.Employee.class, 4);