在hibernate中我们最常用的有三类缓存,分别为一级缓存、二级缓存和查询缓存,下面我们对这三个缓存在项目中的使用以及优缺点分析一下。 缓存它的作用在于提高性能系统性能,介于应用系统与数据库之间而存在于内存或磁盘上的数据。 我们编程的模式一般是这样的page-->filter-->action-->server-->dao-->db,可以在这一个请求过程中的任何一点加入缓存,上一篇介绍的是在server层加缓存:service利用aop加缓存。 为页面增加缓存:为页面加缓存 首先,来看一下一级缓存它默认开启且很常用。 一级缓存
当session关闭后缓存中的对象会丢失,也就是说两个不同的session中的缓存数据都是不一样的,缓存数据不能够跨session访问。
缓存数据的数据类型 在一级缓存中缓存的是实体对象,在使用查询方法get() 、load() 、iterate()三个方法查询时都会先查询session缓存,如果有对象则从缓存里面取出来,如果缓存中没有再去数据库里面查询。load()测试:测试注意一定要在同一个事务里面,当我在Spring管理的session测试时调用两次load()总是查询两次发出两条SQL语句,还以为session级缓存没有起作用,原来是因为hibernate集成spring之后事务、session都由spring管理,每次调用前后事务一级session都自动打开和关闭,自己控制不了中间过程,于是将spring去掉拿到hibernate原session,再手动开发关闭事务这样做可以保证在同一个session、同一个事务里面操作方法,确实是发了一条SQL语句,看下面代码: load()、get()方法:
结果
结果不仅发送了一条语句而且两个对象打印出来也是一样的。 load()、get()第一次查询时会发出sql语句,从数据库表里面查询;第二次查询时会先去缓存里面查找,如果没有发生更新修改操作,那么将从缓存中读取数据,否则查询数据库。 save方法
save也支持缓存,当执行save方法时首先往session缓存里面添加一条数据,等事务提交或者缓存刷新时才往数据库里面更新,从上面执行过程可以看出只发出了一条插入语句没有发查询语句,因为第二次是从缓存中查询出来的。 PS:save之后执行get或者load需要知道对象的ID,此时save方法执行后虽然数据库里没有数据,但是对象的ID已经生成可以通过这个ID查询对象。 批量插入数据 在批量插入数据的时候采取每次插入一部分数据,如下,每次插入20条数据不需要一条一条插入。
每次20条数据清理一下缓存,每次清理缓存调用session.flush()方法会发出20条insert语句,但是数据库里面还没有数据等所有数据都发出insert语句统一提交事务,事务同session是一个等级的因此需统一控制事务。
hibernate N+1问题 Hibernate 中常会用到 set 等集合表示 1 对多的关系,在我们做的这个铁科院项目中,在获取实体的时候就能根据关系将关联的对象或者对象集合取出,还可以设定 cacade 进行关联更新和删除。这不得不说 hibernate 的 orm 做得很好,很贴近 oo 的使用习惯了。
OpenSessionInview问题 这个问题出现是由于load()懒加载导致的,第一次查询数据时使用了懒加载至查询出来数据的ID,当使用数据的时候还需要去数据库里面查询但是此时数据库的session已经关闭,解决此问题两种思路一种是不使用懒加载;其二是在web层开发关闭session,延长session的生命周期。
二级缓存
二级缓存也称为进程级缓存或sessionFactory缓存,也可以叫做集群范围内的缓存,需要第三方来实现,hibernate默认的二级缓存插件为ehcache这个缓存,由于二级缓存是进程级的可能出现多线程并发问题,需要设置缓存的并发策略。 hibernate二级缓存需要第三方插件支持,hibernate默认支持为ehcache关于配置请参考:Spring AOP +EHcache为Service层方法增加缓存
开启二级缓存后对方法的影响 get()/load() 对于这两个方法没啥影响,第一次从数据库里面查询,第二次先判断缓存里面有没有数据如果没有再去数据库里面查询。
查询缓存
查询缓存是针对普通属性结果集的缓存,不缓存实体对象,当和查询缓存关联的表发生修改的时候,查询缓存生命周期结束,里面的数据也随即被清空了。
代码中,加上一句话
一级、二级、查询之间的关系
开启二级缓存时,如果两个session先后执行load或者get方法,只执行一条语句第二次会从缓存中查找,先从一级缓存中查询,如果没有再去二级缓存中查找。 一级缓存同二级缓存交互
禁止一级缓存与二级缓存交互,如下设置 session.setCacheMode(CacheMode.IGNORE);打开一个session执行查询,它会先将查询结果保存到一级缓存,待session关闭后,一级缓存中数据清空,由于禁止了一级缓存同二级缓存数据交互,因此,一级缓存关闭后不会将结构保存到二级缓存,打开第二个session后,后再发送一条查询语句,因此二级缓存中没有数据。 查询缓存与二级缓存
如果两次执行query.list(),第一次发送查询语句会将结果对象的id保存到查询缓存中,第二次会先从查询缓存中取出ID,根据id先去一级缓存查找,再二级缓存,如果没有找到会去数据库中查找,一级缓存同session没有关系,只和表有关系。
开启查询,开启二级缓存 两次执行query.list(),第一次发送查询语句将结果
总结: 缓存在一个项目中对于提高系统性能很重要,除了ehcache之外还有memcache、redis等缓存产品目前都很常用,redis具有丰富的数据类型以及单线程高效能访问效率,memcache虽然是多线程但效率还是没有redis高。 这些缓存产品都可以实现分布式缓存,ehcache+rmi可以分布式缓存同步;memcache+redis都支持分布式,redis还提供了高可用性的解决方案:主从复制几个服务器直接爱你可以切换。
|
|
来自: chengkunzhang > 《hibernate》