hibernate5(6)操纵对象入门[1]Session缓存

简介: <div class="markdown_views"><h1 id="java对象在jvm中的存活条件">java对象在JVM中的存活条件</h1><p>在java中,我们使用<code>User user = new User();</code>来创建一个java对象时,JVM会为其分配一块内存空间,此时,这个对象被变量“user”引用,那么它就会一直存在于内存中,而

java对象在JVM中的存活条件

在java中,我们使用User user = new User();来创建一个java对象时,JVM会为其分配一块内存空间,此时,这个对象被变量“user”引用,那么它就会一直存在于内存中,而如果我们我们的“引用者user”升级了,User user = new VipUser()。那么原来new User()不再被任何变量引用,它就会结束自己的生命周期,然后会被JVM的智能垃圾回收期回收处理,以免再占用内存。
从以上分析,我们知道了java对象存活的条件就是:被(至少一个)变量引用

hibernate的对象存活条件

同样的,假设在我们使用hibernate访问数据库获取了一个小A对象,这个小A一样有它的存活条件,但与一般java对象不同,即使我们没有创建任何变量来引用小A,我们的小A还是能够活得好好的,这是因为小A被hibernate的Session缓存下来了。

理解Session的缓存机制

1. 缓存的实现机制:

在Session接口的实现类中,我们定义了一系列的java集合来存放从数据库中获取的数据,只要我们的Session实例没有结束声明周期,那么存放其中的对象就不会结束其生命周期。

2. Session缓存的作用

1. 减少对数据库的访问次数,优化性能。

比如我们来看下面的例子

Long time1 = System.currentTimeMillis();//记录时间
User user1_1 = session.get(User.class,1);
Long time2 = System.currentTimeMillis();//记录结束时间1
System.out.println("user1_1获取完毕,耗时:"+(time2 - time1)+"毫秒,准备开始获取user1_2");
User user1_2 = session.get(User.class,1);//与上面id相同
System.out.println("user1_2获取完毕,耗时:"+(System.currentTimeMillis() - time2 )+"毫秒,准备开始获取user2");
User user2 = session.get(User.class,2);
System.out.println(user1_1 == user1_2);
System.out.println(user1_2== user2);

运行程序,观察我们的打印信息:

Hibernate: select user0_.id as id1_0_0_, user0_.name as name2_0_0_ from t_user2 user0_ where user0_.id=?
user1_1获取完毕,耗时:26毫秒,准备开始获取user1_2
user1_2获取完毕,耗时:0毫秒,准备开始获取user2
Hibernate: select user0_.id as id1_0_0_, user0_.name as name2_0_0_ from t_user2 user0_ where user0_.id=?
true
false
在我们获取user1_2时,并没有查询数据库而且获取时间几乎为0,说明是直接从缓存中读取的,而在比较对象属性中,user1_1和user1_2相等,说明它们的引用地址也相同,而且必定与session缓存中的引用地址一致
从上面我们还能看到,Session标识缓存的不同对象,是通过对象类型和对象标识符id共同判别的,一旦两者一致,session即判别为同一对象,同时,我们也可归纳出利用session查询数据库的过程:比如我们要查询id为1的User,则查询过程如下时序图所示:

Created with Raphaël 2.1.0SessionSessionSession缓存Session缓存数据库数据库:1. 查找缓存是否有对象类型为User且id为12. 找到并返回2. 没找到则查询数据库3. 返回数据结果并缓存4. 返回数据到引用变量

2. 保证数据库中的记录和缓存中的相应对象内容一致

在session清理缓存(flush)时,会进行脏检查,如果发现缓存中的最新数据与数据库记录不一致,会将最新数据更新到数据库中。
那么,session是如何进行脏检查的呢?难道每次清理前,针对所有的缓存数据访问数据库来进行匹对?这样效率太低了。实际上,在上述时序图的第3步到第4步之间,Session会将获得的数据结果先copy一份(这份copy还未经任何处理,肯定是和数据库记录一致的),再返回给引用变量。这样我们将所有最新的数据与最初copy的校对一下,一旦出现差异,就将最新数据更新到数据库。

3. Session缓存的清理

在我们每次针对引用变量修改对象属性后,对应的Session缓存中的数据也会被修改,这是显然的,因为它们的所指向的内存地址是一致的。但修改后,hibernate并不会马上执行相应的数据库操作,只有在特定条件下,如session被清理特定的方法被调用才会访问数据库。这里谈谈session被清理的三个时间点:
1. 在完成事务提交之前,session会被清理一次。这样的好处是一方面可以减少在事务作用过程中,大量执行的数据库记录修改操作。另一方面还可以尽可能缩短当前事务对相关资源的锁定时间
2. 在执行一些复杂的查询操作时,需要清理缓存,更新数据库,确保查询得到的数据是最新的。
3. 显示地调用Session.flush()方法

如果我们不希望在上述的某些时刻清理,我们可以通过Session的setFlushMode()方法来定制,它提供了3种模式共我们选择:

模式 复杂查询方法被执行 事务提交时 显式调用flush() 使用场景
FlushMode.AUTO(默认模式) 清理 清理 清理 正常应用场景
FlushMode.COMMIT 不清理 清理 清理 需要避免过多查询操作清理缓存以提高性能的场景
FlushMode.NEVER 不清理 不清理 清理 需要长时间运行的复杂事务场景

tips:从上面我们还能看出,我们要修改用户信息,完全用显式地执行session.update(user)语句,只需直接修改Session缓存对象属性即可,如下所示

user.setName("newName");
session.flush();

我们数据库中相应的User记录name属性也被修改了!

此外,Session在清理缓存时,按照以下顺序执行sql语句。
1。按照应用程序调用save()方法的先后顺序,执行所有的对实体进行插入的insert语句。
2。所有对实体进行更新的update语句。
3。所有对实体进行删除的delete语句。
4。所有对集合元素进行删除、更新或插入的sql语句。
5。执行所有对集合进行插入的insert语句。
6。按照应用程序调用delete()方法的先后执行,执行所有对实体进行删除的delete语句。

目录
相关文章
|
2月前
|
缓存 NoSQL Java
springboot的缓存和redis缓存,入门级别教程
本文介绍了Spring Boot中的缓存机制,包括使用默认的JVM缓存和集成Redis缓存,以及如何配置和使用缓存来提高应用程序性能。
130 1
springboot的缓存和redis缓存,入门级别教程
|
4月前
|
缓存 Java Spring
Spring缓存实践指南:从入门到精通的全方位攻略!
【8月更文挑战第31天】在现代Web应用开发中,性能优化至关重要。Spring框架提供的缓存机制可以帮助开发者轻松实现数据缓存,提升应用响应速度并减少服务器负载。通过简单的配置和注解,如`@Cacheable`、`@CachePut`和`@CacheEvict`,可以将缓存功能无缝集成到Spring应用中。例如,在配置文件中启用缓存支持并通过`@Cacheable`注解标记方法即可实现缓存。此外,合理设计缓存策略也很重要,需考虑数据变动频率及缓存大小等因素。总之,Spring缓存机制为提升应用性能提供了一种简便快捷的方式。
63 0
|
4月前
|
Java 数据库连接 数据库
告别繁琐 SQL!Hibernate 入门指南带你轻松玩转 ORM,解锁高效数据库操作新姿势
【8月更文挑战第31天】Hibernate 是一款流行的 Java 持久层框架,简化了对象关系映射(ORM)过程,使开发者能以面向对象的方式进行数据持久化操作而无需直接编写 SQL 语句。本文提供 Hibernate 入门指南,介绍核心概念及示例代码,涵盖依赖引入、配置文件设置、实体类定义、工具类构建及基本 CRUD 操作。通过学习,你将掌握使用 Hibernate 简化数据持久化的技巧,为实际项目应用打下基础。
363 0
|
4月前
|
缓存 中间件 数据库
Django入门到放弃之缓存及信号机制
Django入门到放弃之缓存及信号机制
|
4月前
|
缓存 安全 Java
|
4月前
|
缓存 安全 Java
Hibernate 中的 Session 是线程安全的吗?
【8月更文挑战第21天】
59 0
|
4月前
|
缓存 安全 Java
Hibernate 中的 Session 是什么?
【8月更文挑战第21天】
75 0
|
5月前
|
存储 缓存 算法
同时使用线程本地变量以及对象缓存的问题
【7月更文挑战第15天】同时使用线程本地变量和对象缓存需小心处理以避免数据不一致、竞争条件及内存泄漏等问题。线程本地变量使各线程拥有独立存储,但若与对象缓存关联,可能导致多线程环境下访问旧数据。缺乏同步机制时,多线程并发修改缓存中的共享对象还会引起数据混乱。此外,若线程结束时未释放对象引用,可能导致内存泄漏。例如,在Web服务器场景下,若一更新缓存而另一线程仍获取旧数据,则可能返回错误信息;在图像处理应用中,若多线程无序修改算法对象则可能产生错误处理结果。因此,需确保数据一致性、避免竞争条件并妥善管理内存。
|
5月前
|
存储 缓存 算法
Java面试题:给出代码优化的常见策略,如减少对象创建、使用缓存等。
Java面试题:给出代码优化的常见策略,如减少对象创建、使用缓存等。
71 0
|
6月前
|
Java 数据库连接
杨老师课堂之JavaEE三大框架Hibernate入门第一课
杨老师课堂之JavaEE三大框架Hibernate入门第一课
42 0