Session缓存其实就是一块内存空间,在这个内存空间中存放了互相关联的Java对象,Session负责根据持久化对象的状态变化来同步更新数据库.Session的缓存是内置的,不能被卸载,也被称为Hibernate的第一级缓存,此外SessionFactory有一个内置的缓存和一个外置的缓存,其中外置的缓存是可插拔的缓存插件,也被称为Hibernate的第二级缓存,在默认情况下,SessionFactory不会启动这个缓存插件.
缓存的范围和缓存的并发访问策略
1.持久层的缓存范围
事务范围: 缓存只能被当前事务访问,缓存的生命周期依赖于事务的生命周期.每个事务都有独自的缓存
进程范围: 缓存被进程内的所有事务共享,缓存的生命周期依赖于进程的生命周期. 因为进程的事务有可能并发访问缓存,所以必须对缓存采取必要的事务隔离机制;
群集范围: 在群集环境中, 缓存被同一个机器或多个机器上的多个进程共享. 缓存中的数据被复制到集群环境中的每个进程节点,进程之间通过远程通信来保证缓存中数据的一致性,
缓存中的数据通常采用对象的散装数据形式;
2.缓存并发访问策略
由上可见, 进程范围或群集范围缓存,即第二级缓存,会出现并发问题.对第二级缓存可以设定以下四种类型的并发访问策略,每一个策略对应一种事务隔离级别.
1) 事务型: 仅仅在受管理环境中适用,对于经常被读但是很少被修改的数据,可以防止脏读和不可重复读的并发问题;
2)读写型: 仅仅在非群集的环境中适用,对于经常被读但是很少被修改的数据,可以防止脏读;
3)非严格读写型: 不保证缓存与数据库中数据的一致性,对于极少被修改,并且允许偶尔脏读的数据,可以采用这种策略;
4)只读型: 对于从来不会被修改的数据,如参考数据,可以使用这个策略;
只有符合以下条件的数据才适合于存放到第二级缓存中:
1) 很少被修改的数据;
2) 不是很重要的数据,允许出现偶尔的并发问题;
3)不会被并发访问的数据;
4)参考数据;
Hibernate的二级缓存SessionFactory是进程范围或群集范围的缓存,因此需要采用适当的并发访问策略,提供事务隔离级别,而且可以在每个类或每个集合的粒度上配置第二级缓存.缓存适配器(Cache Provider)用于把具体的缓存实现软件于Hibernate集成.Hibernate还为查询结果提供了一个查询缓存,它依赖于第二级缓存.
管理Hibernate的第一级缓存
Session为应用程序提供了两个管理缓存方法evict(Object o)和clear()
evict(Object o) : 从缓存中清除参数指定的持久化对象;(适用于不希望session'按照该对象的状态变化来同步更新数据库和批量更新或批量删除的场合)
clear(): 清空缓存中所有持久化对象
*对于更好的批量更新或者批量删除的场合应该直接通过JDBC API访问数据库的过程, 执行SQL语句来减少Hibernate API的多次sql执行, 或者调用相关的存储过程. 这个时候还得注意
Transaction接口来声明事务边界;
管理Hibernate的第二级缓存
由于第二级缓存是可配置的插件,Hibernate允许选用以下类型的缓存插件:
1) EHCache: 进程范围内的缓存, 对Hibernate的查询缓存提供了支持;(net.sf.hibernate.cache.EhCacheProvider EHCache插件的适配器)
2) OpenSymphony OSCache: 进程范围内的缓存,提供了丰富的缓存数据过期策略,对Hibernate的查询缓存提供了支持;(net.sf.hibernate.cache,OSCacheProvider OSCache插件
的适配器);
3) SwarmCache: 群集范围的缓存,但不支持Hibernate的查询缓存;(net.sf.hibernate.cache.SwarmCacheProvider SwarmCache插件的适配器)
4) JBossCache: 群集范围内的缓存,支持事务并发访问策略,对Hibernate的查询缓存提供了支持;(net.sf.hibernate,cache.TreeCacheProvider JBossCache插件的适配器)
配置第二级缓存主要包含以下步骤:
1) 在各个映射文件中为持久化类设置第二级缓存后者在Hibernate的配置文件hibernate.cfg.xml中集中设置第二级缓存,设置它的命名缓存的并发访问策略;
2)选择合适的缓存插件,手工编辑配置文件,为每个命名缓存设置数据过期策略;
<class name="mypack.Category" table="CATEGORIES">
<cache usage="read-write"/>
<id name="id" type="long" column="ID">
...
</class>
*如果只在category中配置cache,当调用category.getItems().iterate()方法时,Hibernate只会把items集合中的元素存放到缓存中,此时Hibernate仅仅把与Category关联的Item对象的OID存放
到缓存中.如果希望把整个Item对象散装数据存入缓存,应该在Item.hbm.xml文件中设置cache元素
***************************************************************************************************************************************************
在默认情况下,Session会在下面的时间点清理缓存.
1) 当应用程序调用net.sf.hibernate.Transaction的commit()方法的时候,commit()方法先清理缓存, 然后再向数据库提交事务;
2) 当应用程序调用Session的find()或者iterate()时, 如果缓存中持久化对象的属性发生了变化, 就会先清理缓存, 以保证查询结果能反映持久化对象的最新状态;
3) 当应用程序显式调用Session的flush()方法的时候;
1. Session的save()方法
save方法并不立即执行SQL insert语句, 只有当Session清理缓存的时, 才会执行SQL insert语句.如果在save()方法之后, 又修改了持久化对象的属性, 这会使得Session在清理缓
存时, 额外执行SQL update语句.
2. Session的update()方法
update方法会生成或调用一个计划的update语句,并且Session只有在清理缓存的时候才会执行update语句,在执行时才会把Customer对象当前的属性值组装到update语句中.
**通过update()方法使游离对象被一个Session关联,即使没有修改Customer对象的任何属性,Session在清理缓存时也会执行由update()方法计划的update语句. 如果希望Session仅仅当修
改了Customer对象的属性时, 才执行update语句, 可以把映射文件中<class>元素的select-before-update设为true, 该属性的默认值为false;
**当update()方法关联一个游离对象时, 如果在Session的缓存中已经存在相同OID的持久化对象,会抛出异常.
3. Session的saveOrUpdate()方法
saveOrUpdate()方法同时包含了save()与update()方法的功能, 如果传入的参数是临时对象就调用save()方法; 如果传入的参数是游离对象, 就调用update()方法; 如果传入的参数
是持久化对象, 那就直接返回.
4. Session的load()和get()方法
Session的load()和get()方法都能根据给定的OID从数据库中加载一个持久化对象, 这两个方法的区别在于: 当数据库中不存在与OID对应的记录时, load()方法抛出
net.sf.hibernate.ObjectNotFoundException异常,而get()返回null.
5. Session的delete()方法
如果传入的参数是持久化对象, Session就计划执行一个delete语句. 如果传入的参数是游离对象, 先使游离对象被Session关联, 使它变为持久化对象, 然后计划执行一个delete语
句. Session只有在清理缓存的时候才会执行delete语句.
该方法也能删除多个对象, 但不推荐,效率低.如 session.delete("from Customer as c where c.id>8");