Hibernate

一、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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值