一、Session
Session:是应用程序与数据库之间的一个会话,是hibernate运作的中心,持久层操作的基础。对象的生命周期/事务的管理/数据库的存取都与Session息息相关,Session对象是通过SessionFactory构建的。
1、session.clear 强制清除Session缓存,把缓冲区内的全部对象清除,但不包括操作中的对象
2、session.evict(obj),会把指定的缓冲对象进行清除
3、session.refresh 刷新,保证 一级缓存的数据 与 数据库的数据 保持一致
4、session.flush
session flush在commit之前默认都会执行, 也可以手动执行,他主要做了两件事:
1) 清理缓存。
2) 执行SQL(但不提交transaction)。
flush: Session 按照缓存中对象属性变化来同步更新数据库。
默认情况下,Session 会在以下情况下调用 flush:
a. 直接调用 session.flush。
b. 当应用调用Transaction.commit() 时, 会先调用 flush, 然后再向数据路提交。
c. 在做查询时(HQL, Criteria),如果缓存中持久化对象的属性发生变化,会先 flush 缓存,以保证查询结果是最新的数据。
参考:https://www.cnblogs.com/mid-wk/p/7120563.html
二、关于Hibernate缓存
Hibernate缓存分为二级:第一级存放于session中称为一级缓存,默认带有且不能卸载;第二级是由sessionFactory控制的进程级缓存,是全局共享的缓存;
查询时使用缓存的实现过程为:首先查询一级缓存中是否具有需要的数据,如果没有,查询二级缓存,如果二级缓存中也没有,此时再执行查询数据库的工作。要注意的是:此3种方式的查询速度是依次降低的。
1、一级缓存的问题以及使用二级缓存的原因
Session内部缓存的主要作用是保持Session内部数据状态同步。并非是hibernate为了大幅提高系统性能所提供的。(Session的生命期往往很短,存在于Session内部的第一级最快缓存的生命期当然也很短,所以第一级缓存的命中率是很低的。其对系统性能的改善也是很有限的)
配置hibernate的二级缓存。其对系统整体性能的改善往往具有立竿见影的效果!
2、关于数据的有效性
hibernate会自行维护二级缓存中的数据,以保证缓存中的数据和数据库中的真实数据的一致性!
只要是调用hibernate API执行数据库相关的工作。hibernate都会为你自动保证 缓存数据的有效性!
如果你使用了JDBC绕过hibernate直接执行对数据库的操作。此时,hibernate不会/也不可能自行感知到数据库被进行的变化改动,也就不能再保证缓存中数据的有效性!
这也是所有的ORM产品共同具有的问题。幸运的是,hibernate为我们暴露了Cache的清除方法,这给我们提供了一个手动保证数据有效性的机会!
一级缓存,二级缓存都有相应的清除方法。
其中二级缓存提供的清除方法为:
按对象class清空缓存
按对象class和对象的主键id清空缓存
清空对象的集合中的缓存数据等。
3、合适使用的情况
a.数据不会被第三方修改
b.数据大小在可接收范围之内
c.数据更新频率低
d.非关键数据(不是财务数据等,财务数据等是非常重要的数据,绝对不允许出现或使用无效的数据,所以此时为了安全起见最好不要使用二级缓存。 因为此时 “正确性”的重要性远远大于 “高性能”的重要性)
hibernate缓存参考文档:https://blog.youkuaiyun.com/woshichenxu/article/details/586361
启用二级缓存参考:https://www.cnblogs.com/bigben0123/p/8257071.html
一级缓存参考:https://www.cnblogs.com/fjkgrbk/p/hibernate_catch.html
三、hibernate性能调优
<property name="hibernate.jdbc.fetch_size">50</property>
<property name="hibernate.jdbc.batch_size">30</property>
Fetch Size
Fetch Size 是设定JDBC的Statement读取数据的时候每次从数据库中取出的记录条数。
例如一次查询1万条记录,对于Oracle的JDBC驱动来说,是不会1次性把1万条取出来的,而只会取出Fetch Size条数,当纪录集遍历完了这些记录以后,再去数据库取Fetch Size条数据。
因此大大节省了无谓的内存消耗。当然Fetch Size设的越大,读数据库的次数越少,速度越快;Fetch Size越小,读数据库的次数越多,速度越慢。
这有点像平时我们写程序写硬盘文件一样,设立一个Buffer,每次写入Buffer,等Buffer满了以后,一次写入硬盘,道理相同。
Oracle数据库的JDBC驱动默认的Fetch Size=10,是一个非常保守的设定,根据我的测试,当Fetch Size=50的时候,性能会提升1倍之多,当Fetch Size=100,性能还能继续提升20%,Fetch Size继续增大,性能提升的就不显著了。
因此我建议使用Oracle的一定要将Fetch Size设到50。
不过并不是所有的数据库都支持Fetch Size特性,例如MySQL就不支持。
Batch Size
Batch Size是设定对数据库进行批量删除,批量更新和批量插入的时候的批次大小,有点相当于设置Buffer缓冲区大小的意思。
Batch Size越大,批量操作的向数据库发送sql的次数越少,速度就越快。我做的一个测试结果是当Batch Size=0的时候,使用hibernate对Oracle数据库删除1万条记录需要25秒,Batch Size = 50的时候,删除仅仅需要5秒!!!
hibernate批处理操作优化(批量插入、更新、删除)
主要原因:hibernate的一级缓存影响
如果我们一直循环执行save等操作,缓存里东西会越来越多,速度也就越来越慢,自然也会增加负载。
解决方案:
a、设置hibernate.jdbc.batch_size参数,指定每次提交SQL的数量,减少数据库访问
b、程序及时清理缓存
c、使用JDBC API来做,绕过hibernate API,这个方法性能上最快,但要注意手动同步hibernate缓存
参考:https://www.cnblogs.com/jiligalaer/p/5564982.html
参考:https://github.com/Shellbye/Shellbye.github.io/issues/49
参考:http://www.360doc.com/content/13/1227/12/15077105_340502932.shtml
参考:https://www.cnblogs.com/xhj123/p/6106088.html
四、hibernate三态
1, 临时状态(Transient):也叫自由态,只存在于内存中,而在数据库中没有相应数据。用new创建的对象,它没有持久化,没有处于Session中,处于此状态的对象叫临时对象;
2, 持久化状态(Persistent):与session关联并且在数据库中有相应数据。已经持久化,加入到了Session缓存中。如通过hibernate语句保存的对象。处于此状态的对象叫持久对象;
3, 游离状态(Detached):持久化对象脱离了Session的对象。如Session缓存被清空的对象。
特点:已经持久化,但不在Session缓存中。处于此状态的对象叫游离对象;
×√ | 临时状态 (Transient) | 持久化状态 (Persistent) | 游离状态 (Detached) |
是否处于Session缓存中 | × | √ | × |
数据库中是否有对应记录 | × | √ | √ |
|
|
|
|
Spring整合Hibernate参考:https://www.cnblogs.com/sam-uncle/p/8681515.html