通过示例了解 Hibernate 一级缓存

通过示例了解 Hibernate 一级缓存

原文: https://howtodoinjava.com/hibernate/understanding-hibernate-first-level-cache-with-example/

缓存是 ORM 框架提供的一项功能,可帮助用户获得快速运行的 Web 应用,同时帮助框架本身减少单个事务中对数据库的查询数量。 Hibernate 通过实现一级缓存来实现第二个目标。

Hiberate 中的第一级缓存默认情况下处于启用状态,并且您无需执行任何操作即可使此功能正常工作。 实际上,您甚至不能强行禁用它。

如果我们了解与会话对象关联的事实,那么就很容易理解第一级缓存。 我们知道,会话对象是按需从会话工厂创建的,一旦会话关闭就会丢失。 同样,与会话对象关联的一级缓存仅在会话对象处于活动状态之前可用。 它仅对会话对象可用,并且对于应用任何其他部分中的任何其他会话对象均不可访问。

Hibernate first level cache

重要事实

  1. 一级缓存与“会话”对象关联,应用中的其他会话对象看不到它。
  2. 缓存对象的范围是会话。 一旦会话关闭,缓存的对象将永远消失。
  3. 默认情况下,第一级缓存处于启用状态,您不能禁用它。
  4. 当我们第一次查询实体时,它是从数据库中检索出来的,并存储在与 Hiberate 会话相关的一级缓存中。
  5. 如果我们使用相同的会话对象再次查询相同的对象,则会从缓存中加载该对象,并且不会执行任何 SQL 查询。
  6. 可以使用evict()方法从会话中删除已加载的实体。 如果已使用evict()方法删除了该实体,则该实体的下一次加载将再次进行数据库调用。
  7. 可以使用clear()方法删除整个会话缓存。 它将删除所有存储在缓存中的实体。

让我们使用示例验证以上事实。

一级缓存检索示例

在此示例中,我使用 Hiberate 会话从数据库中检索DepartmentEntity对象。 我将多次检索它,并将观察 sql 日志以查看差异。

//Open the hibernate session
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();

//fetch the department entity from database first time
DepartmentEntity department = (DepartmentEntity) session.load(DepartmentEntity.class, new Integer(1));
System.out.println(department.getName());

//fetch the department entity again
department = (DepartmentEntity) session.load(DepartmentEntity.class, new Integer(1));
System.out.println(department.getName());

session.getTransaction().commit();
HibernateUtil.shutdown();

Output:

Hibernate: select department0_.ID as ID0_0_, department0_.NAME as NAME0_0_ from DEPARTMENT department0_ where department0_.ID=?
Human Resource
Human Resource

如您所见,第二个“session.load()”语句不会再次执行select查询并直接加载部门实体

使用新会话的一级缓存检索示例

对于新会话,无论实体是否已存在于应用的任何其他会话中,都将从数据库中再次获取实体。

//Open the hibernate session
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();

Session sessionTemp = HibernateUtil.getSessionFactory().openSession();
sessionTemp.beginTransaction();
try
{
	//fetch the department entity from database first time
	DepartmentEntity department = (DepartmentEntity) session.load(DepartmentEntity.class, new Integer(1));
	System.out.println(department.getName());

	//fetch the department entity again
	department = (DepartmentEntity) session.load(DepartmentEntity.class, new Integer(1));
	System.out.println(department.getName());

	department = (DepartmentEntity) sessionTemp.load(DepartmentEntity.class, new Integer(1));
	System.out.println(department.getName());
}
finally
{
	session.getTransaction().commit();
	HibernateUtil.shutdown();

	sessionTemp.getTransaction().commit();
	HibernateUtil.shutdown();
}

Output:

Hibernate: select department0_.ID as ID0_0_, department0_.NAME as NAME0_0_ from DEPARTMENT department0_ where department0_.ID=?
Human Resource
Human Resource

Hibernate: select department0_.ID as ID0_0_, department0_.NAME as NAME0_0_ from DEPARTMENT department0_ where department0_.ID=?
Human Resource

您可以看到,即使部门实体存储在“session”对象中,当我们使用另一个会话对象“sessionTemp”时,仍然执行了另一个数据库查询。

从一级缓存中删除缓存对象的示例

尽管我们不能在 Hiberate 中禁用一级缓存,但是我们可以在需要时从其中删除一些对象。 这可以通过两种方法完成:

  • evct()
  • clear()

这里evict()用于从与会话关联的缓存中删除特定对象,clear()方法用于从会话关联的缓存中删除所有对象。 因此,它们本质上就像删除一个并删除所有。

//Open the hibernate session
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
try
{
	//fetch the department entity from database first time
	DepartmentEntity department = (DepartmentEntity) session.load(DepartmentEntity.class, new Integer(1));
	System.out.println(department.getName());

	//fetch the department entity again
	department = (DepartmentEntity) session.load(DepartmentEntity.class, new Integer(1));
	System.out.println(department.getName());

	session.evict(department);
	//session.clear(); 

	department = (DepartmentEntity) session.load(DepartmentEntity.class, new Integer(1));
	System.out.println(department.getName());
}
finally
{
	session.getTransaction().commit();
	HibernateUtil.shutdown();
}

Output:

Hibernate: select department0_.ID as ID0_0_, department0_.NAME as NAME0_0_ from DEPARTMENT department0_ where department0_.ID=?
Human Resource
Human Resource

Hibernate: select department0_.ID as ID0_0_, department0_.NAME as NAME0_0_ from DEPARTMENT department0_ where department0_.ID=?
Human Resource

显然,evict()方法从高速缓存中删除了部门对象,以便再次从数据库中获取它。

希望你喜欢上面的文章。 如果您有任何问题或建议,请发表评论。

学习愉快!