【SSH进阶之路】【六】hibernate5 操纵对象入门【1】Session缓存

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查询数据库的过程:比如我们要查询id1的User,则查询过程如下时序图所示:


这里写图片描述

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

在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语句。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

帅胖子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值