hibernate一级缓存

理解 Hibernate 一级缓存

Hibernate 一级缓存默认是打开,不需要任何的配置。实际上,你无法强制禁止它的使用。 如果你理解了一级缓存实际上和会话是关联的,就很容易理解一级缓存。总所周知,会话是当我们需要时从会话工厂创建并且一旦会话关闭,缓存就会丢失。相似的,一级缓存与会话对象相关联,在会话存活期间是可用的。相同应用中的不同会话是无法相互访问的。

重点

  • 一级缓存和会话相关联,应用中的会话无法知道其他会话中的缓存
  • 缓存的范围是在会话范围内。一旦会话被关闭,缓存将永远消失
  • 一级缓存默认是打开的,并无法禁止
  • 第一次查询一个实体会从数据库中检索,并被存放在与 hibernate 会话关联的一级缓存中
  • 如果在一个会话中再次查询该实体,它将从一级缓存中加载,不会发送 sql 查询到数据库
  • 加载的实体可以从会话中被移除,通过使用 evict() 方法。如果实体已经使用 evict 下次加载该实体将会再次调用数据库查询
  • 整个会话缓存可以通过 clear() 方法移除。它将移除缓存中的所有实体

从一级缓存检索的例子

在下面的例子中,将通过 hibernate 会话从数据库检索 Department 实体。多次检索该实体,观察 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 查询,而是直接加载 department 实体。说明实体对象却是被缓存了。

新会话测试一级缓存

如果实体已经在一个会话中被获取,在新会话中,该实体将再次从数据库中获取。

//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

从输出可以发现及时 department 实体已经被存储在会话中,但是 sessionTemp 会话还是发出了一条数据库查询语句。说明不同会话之间的缓存是相互不可见的。

将实体对象从一级缓存中移除

虽然无法禁用 hibernate 一级缓存,但是如果需要的话,可以移除该缓存对象。通过使用一下两个方法:

  • evict()
  • 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() 方法将 department 实体从一级缓存中移除,所以他再次从数据库中获取。

本文内容来自:http://howtodoinjava.com/hibernate/understanding-hibernate-first-level-cache-with-example/。本文只是翻译以及润色

欢迎转载,但请注明本文链接,谢谢你。 2016.9.21 9:08

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Petrichor的专栏

AttributeError: 'module' object has no attribute 'fullmatch'.

经过查找,发现出错的原因是 re库 中的 fullmatch函数 是 在py3.4之后才新添加的 。

2683
来自专栏Core Net

ASP.NET Core 2.0 : 七.一张图看透启动背后的秘密

3605
来自专栏青玉伏案

JavaEE开发之Spring中的多线程编程以及任务定时器详解

上篇博客我们详细的聊了Spring中的事件的发送和监听,也就是常说的广播或者通知一类的东西,详情请移步于《JavaEE开发之Spring中的事件发送与监听以及使...

2477
来自专栏我爱编程

Day15进程和线程

多进程 multiprocessing multiprocessing模块提供了一个Process类来代表一个进程对象,下面的例子演示了启动一个子进程并等待其结...

2865
来自专栏思考的代码世界

Python基础学习09天

1676
来自专栏javathings

Spring 中,定时任务接口 SchedulingConfigurer

Spring 中,创建定时任务除了使用@Scheduled 注解外,还可以使用 SchedulingConfigurer。

3.4K3
来自专栏Python绿色通道

Python的进程

Python实现多进程的方式主要有两种:一种方法是使用os模块中的fork方法; 另一种是使用multiprocessing模块。这两种方法的区别在于前者仅适用...

952
来自专栏微信公众号:Java团长

Java多线程之并发协作生产者消费者设计模式

1832
来自专栏java、Spring、技术分享

JVM监控及诊断工具

jstat用法 其中-gc可以换成-class 、-gcnew、-gcold等参数;而54992表示的JVM的进程id(可能通过上面的jps命令查看...

3152
来自专栏大内老A

学习ASP.NET Core, 怎能不了解请求处理管道[6]: 管道是如何随着WebHost的开启被构建出来的?

注册的服务器和中间件共同构成了ASP.NET Core用于处理请求的管道, 这样一个管道是在我们启动作为应用宿主的WebHost时构建出来的。要深刻了解这个管道...

4027

扫码关注云+社区

领取腾讯云代金券