通过以上的介绍可以看出hibernate主要从以下几个方面来优化查询性能
降低访问数据库的频率减少select语句的数目实现手段有使用迫切左外连接或迫切内连接对延迟检索或立即检索设置批量检索数目使用查询缓存
避免加载多余的应用程序不需要访问的数据实现手段有使用延迟加载策略使用集合过滤
避免报表查询数据占用缓存实现手段为利用投影查询功能查询出实体的部分属性
减少select语句中的字段从而降低访问数据库的数据量实现手段为利用Query的iterate()方法
Query的iterate()方法首先检索ID字段然后根据ID字段到hibernate的第一级缓存以及第二级缓存中查找匹配的Customer对象如果存在就直接把它加入到查询结果集中否则就执行额外的select语句根据ID字段到数据库中检索该对象
Query query = sessioncreateQuery(from Customer where age<);
Iterator result = erate();
对于经常使用的查询语句如果启用了查询缓存当第一次执行查询语句时hibernate会把查询结果存放在第二级缓存中以后再次执行该查询语句时只需从缓存中获得查询结果从而提高查询性能如果查询结果中包含实体第二级缓存只会存放实体的OID而对于投影查询第二级缓存会存放所有的数据值
查询缓存适用于以下场合在应用程序运行时经常使用的查询语句很少对与查询语句关联的数据库数据进行插入删除更新操作
对查询语句启用查询缓存的步骤如下
配置第二级缓存
在hibernate的配置文件中设置查询缓存属性hibernatecacheuse_query_cache=true
即使设置了缓存在执行查询语句时仍然不会启用查询缓存只有在调用querysetCacheable()后才启用缓存
Query query = sessioncreateQuery(from Customer c where cage > :age);
querysetInteger(age age):
querysetCacheable(true);
如果希望更加精粒度地控制查询缓存可以设置缓存区域querysetCacheRegion(customerQueries);
hibernate提供了种和查询相关的缓存区域
默认的查询缓存区域netsfhibernatecacheStandardQueryCache
用户自定义的查询缓存区域如customerQueries
时间戳缓存区域netsfhibernatecacheUpdateTimestampCache
默认的查询缓存区域以及用户自定义的查询缓存区域都用于存放查询结果而时间戳缓存区域存放了对于查询结果相关的表进行插入更新删除操作的时间戳hibernate通过时间戳缓存区域来判断被缓存的查询结果是否过期当应用进程对数据库的相关数据做了修改hibernate会自动刷新缓存的查询结果但是如果其它应用进程对数据库的相关数据做了修改hibernate无法监测到这一变化此时必须由应用程序负责监测这一变化(如通过发送和接收事件或消息机制)然后手工刷新查询结果
QuerysetForceCacheRefresh(true)方法允许手工刷新查询结果它使得hibernate丢弃查询缓存区域中己有的查询结果重新到数据库中查询数据再把查询结果存放在查询缓存区域中
一个session可以和多个事务对应
Transaction trans = sessionbeginTransaction();
//数据库操作
mit();//提交第一个事务
sessiondisconnect();//释放数据库连接
//执行一些耗时的操作这段操作不属于任何事务
sessionreconnect();//重新获取数据库连接
Transaction trans = sessionbeginTransaction();//开始第二个事务
//数据库操作
mit();//提交第二个事务
注意如果在执行session的一个事务时出现了异常就必须立即关闭这个session不能再利用这个session来执行其它的事务
许多数据库系统都有自动管理锁的功能它们能根据事务执行的SQL语句自动在保证事务间的隔离性与保证事务间的并发性之间做出权衡然后自动为数据库资源加上适当的锁在运行期间还会自动升级锁的类型以优化系统的性能
对于普通的并发性事务通过系统的自动锁定管理机制基本可以保证事务之间的隔离性但如果对数据安全数据库完整性和一致性有特殊要求也可以由事务本身来控制对数据资源的锁定和解锁
数据库系统能够锁定的资源包括数据库表区域页面键值(指带有索引的行数据)行(即表中的单行数据)在数据库系统中一般都支持锁升级以提高性能
按照封锁程序锁可以分为共享锁独占锁更新锁
共享锁用于读数据操作它是非独占的允许其它事务同时读取其锁定的资源但不允许其它事务更新它
独占锁也称排它锁适用于修改数据的场合它所销定的资源其它事务不能读取也不能修改
更新锁在更新操作的初始化阶段用来锁定可能要被修改的资源这可以避免使用共享锁造成的死锁现象
许多的数据库系统能够自动定期搜索和处理死锁问题当检测到锁定请求环时系统将结束死锁优先级最低的事务并且撤销该事务
应用程序中可以采用下面的一些方法尽量避免死锁
合理安排表访问顺序
使用短事务
如果对数据的一致性要求不高可以允许髒读髒读不需要对数据资源加锁可以避免沖突
如果可能的话错开多个事务访问相同数据资源的时间以防止锁沖突
使用尽可能低的事务隔离级别
为了实现短事务在应用程序中可以考虑使用以下策略
如果可能的话尝试把大的事务分解为多个小的事务然后分别执行这保证每个小事务都很快完成不会对数据资源锁定很长时间
应该在处理事务之前就准备好用户必须提供的数据不应该在执行事务过程中停下来长时间等待输入数据
数据库系统提供了四种事务隔离级别供用户选择
Serializable串行化
Repeatable Read可重复读
Read Commited读己提交数据
Read Uncommited读未提交数据
隔离级别越高越能保证数据的完整性和一致性但是对并发性能的影响也越大对于多数应用程序可以优先把数据库系统的隔离级别设为ReadCommited它能够避免髒读而且具有较好的并发性能尽管它会导致不可重复读虚读和第二类丢失更新这些并发问题在可能出现这类问题的个别场合可以由应用程序采用悲观锁或乐观锁来控制
JDBC数据库连接使用数据库系统默认的隔离级别在hibernate的配置文件中可以显式地设置隔离级别(nnectionisolation=)每一种隔离级别都对应一个整数
Read Uncommitted
Read Committed
Repeatable Read
Serializable
在受管理的环境中如果hibernate使用的是数据库连接来自于应用服务器提供的数据源hibernate不会修改这些连接的事务隔离级别在这种情况下应该通过修改应用服务器的数据源配置来修改隔离级别
悲观锁指在应用程序中显式地为数据资源加锁先锁定资源再进行操作尽管悲观锁能够防止丢失更新和不可重复读这类并发问题但是它会影响并发性能因此应该很谨慎地使用悲观锁
乐观锁完全依靠数据库的隔离级别来自动管理锁的工作应用程序采用版本控制手段来避免可能出现的并发问题
悲观锁有两种实现方式在应用程序中显式指定采用数据库系统的独占锁来锁定数据资源在数据库表中增加一个表明记录状态的LOCK字段当它取值为Y时表示该记录己经被某个事务锁定如果为N表明该记录处于空闲状态事务可以访问它
以下select语句指定采用独占锁来锁定查询的记录select for update;执行该查询语句的事务持有这把锁直到事务结束才会释放锁
hibernate可以采用如下方式声明使用悲观锁Account account = (Account)sessionget(Accountclass LockModeUPGRADE);
netsfhibernateLockMode类表示锁模式它的取值如下
LockModeNONE默认值先查缓存缓存没有再去数据库中查
LockModeREAD总是查询数据库如果映射文件设置了版本元素就执行版本比较主要用于对一个游离对象进行版本检查
LockModeUPGRADE总是查询数据库如果映射文件设置了版本元素就执行版本比较如果数据库支持悲观锁就执行 for update否则执行普通查询
LockModeUPGRADE_NOWAIT和UPGRADE功能一样此外对oracle数据库执行 for update nowait; nowait表明如果不能立即获得悲观锁就抛出异常
LockModeWRITE当hibernate向数据库保存或更新一个对象时会自动使用这种模式它仅供hibernate内部使用应用程序中不应该使用它
如果数据库不支持select for update语句也可以由应用程序来实现悲观锁这需要要表中增加一个锁字段lock
hibernate映射文件中的<version>和<timestamp>元素都具有版本控制功能<version>利用一个递增的整数来跟蹤数据库表中记录的版本<timestamp>用时间戳来跟蹤数据库表中记录的版本
version的用法如下
配置文件中<version name=version column=VERSION/>必须紧跟在<id>元素的后面数据库中的version(int)字段与version属性映射
应用程序无需为JavaBean的version属性显示赋值在持久化JavaBean对象时hibernate会自动为它赋初始值在更新数据时hibernate会更新自动version属性update ACCOUNTS set NAME=TomBALANCE=VERSION= where ID= and VERSION=;
如果在此过程中有其它程序操作过此记录那么它的version就会有更新再次执行update语句时会找不到匹配的记录此时hibernate会抛出StaleObjectStateException在应用程序中应该处理这种异常处理方法有两种
自动撤消事务通知用户信息己被其它事务修改需要重新开始事务
通知用户信息己被其它事务修改显示最新数据由用户决定如果继续
只有当hibernate通过update语句更新一个对象时才会修改它的version属性对于存在关联关系的对象只更新发生变化的对象对没有发生变化的关联对象是不会更新的也就是说version不具有级联特性
timestamp用法如下
配置文件和表中各加一个属性(表中是timestamp类型)<timestamp name=lastUpdatedTime column=LAST_UPDATED_TIME />必须紧跟在<id>元素的后面
当持久化一个JavaBean对象时hibernate会自动用当前的系统时间为lastUpdatedTime属性赋值更新时也会用系统时间来更新此字段理论上<version>元素比<timestamp>更安全一些因为<timestamp>只能精确到秒不能处理毫秒内的同步
因此建议使用基于整数的<version>元素
对游离对象进行版本检查如果不一致会抛出StaleObjectStateException()
Transaction trans = sessionbeginTransaction();
sessionlock(account LockModeREAD);//仅仅执行版本检查(与数据库中的最新数据进行比较)而不会保存数据库
mit();
如果数据库中不包含代表版本或时间戳的字段hibernate提供了其它方法实现乐观锁把<class>元素的optimisticlock属性设为all把<class>元素的optimisticlock属性设为all或dirty必须同时把dynamicupdate属性设为true
optimisticlock=true时hibernate更新时会在where子句中包含JavaBean对象被加载时的所有属性
optimisticlock=dirty时hibernate更新时会在where子句中仅包含被更新过的属性
尽管这种方法也能实现乐观锁但是这种方法速度很慢而且只适用于在同一个session中加载了该对象然后又在同一个session中更新了此对象的场合如果在不同的session中会导致第二个session无法知道JavaBean对象被第一个session加载时所有属性的初始值因此不能在update语句的where子句中包含JavaBean对象的属性的初始值因此执行以下update语句update ACCOUNTS set NAME=tomBALANCE= where ID=;这会导致当前事务覆盖其它事务对这条记录己做的更新
hibernate的二级缓存本身的实现很复杂必须实现并发访问策略以及数据过期策略SessionFactory的外置缓存是一个可配置的缓存插件在默认情况下不会启用
二级缓存进程范围或群集范围会出现并发问题对二级缓存可以设定以下四种类型的并发访问策略每一种策略对应一种事务隔离级别
事务型仅仅在受管理环境中适用它提供Repeatable Read事务隔离级别对于经常读但是很少写的数据可以采用这种隔离级别因为它可以防止髒读和不可重复读这类并发问题
读写型提供Read Committed事务隔离级别仅仅在非群集的环境中适用对于经常读但是很少写的数据可以采用这种隔离类型因为它可以防止髒读这类并发问题
非严格读写型不保证缓存与数据库中数据的一致性如果存在两个事务同时访问缓存中相同数据的可能必须为该数据配置一个很短的数据过期时间从而尽量避免髒读对于极少被修改并且允许髒读的数据可以采用这种并发访问策略
只读型对于从来不会写的数据可以使用这种并发访问策略
事务型策略的隔离级别最高只读型的最低事务隔离级别越高并发性能越低如果二级缓存中存放中的数据会经常被事务修改就不得不提高缓存的事务隔离级别但这又会降低并发性能因此只有符合以下条件的数据才适合于存放到二级缓存中
很少被修改不是很重要的数据允许偶尔出现并发问题不会被并发访问的数据参考数据
以下数据不适合于存放到二级缓存中
经常被修改的数据财务数据绝对不允许出现并发问题与其它应用共享的数据
hibernate还为查询结果提供了一个查询缓存它依赖于二级缓存
Session为应用程序提供了两个管理一缓存的方法
evict()从缓存中清除参数指定的持久化对象如果在映射文件关联关系的cascade为all或alldeleteorphan时会级联清除它适用于不希望session继续按照该对象的状态变化来同步更新数据库在批量更新或指量删除的场合当更新或删除一个对象后及时释放该对象占用的内存值得注意的是批量更新或删除的最佳方式是直接通过JDBC API执行相关的SQL语句或者调用相关的存储过程
clear()清空缓存中所有持久化对象
在多数情况下不提倡通过evict()和clear()方法来管理一级缓存因为它们并不能显着地提高应用的性能管理一级缓存的最有效的方法是采用合理的检索策略和检索方式如通过延迟加载集合过滤投影查询等手段来节省内存开销
hibernate中直接通过JDBC API来执行更新或删除操作的方法如下
Transaction trans = sessionbeginTransaction();
Connection conn = nnection();
PreparedStatement statement = connprepareStatement(update ACCOUNTS set AGE=AGE+ where AGE>);
statementexecuteUpdate();
mit();
如果底层数据库支持存储过程也可以直接调用存储过程来执行指量更新
Transaction trans = sessionbeginTransaction();
Connection conn = nnection();
CallableStatement statement = connprepareCall({call batchUpdateCustomer(?)});
statementsetInt( );//把第个参数的值设为
statementexecuteUpdate();
mit();
hibernate中session的各种重载的update()方法一次都只能更新一个对象而delete()方法有些重载形式允许以HQL语句作为参数如
sessiondelete(from Customer c where cage>);
但是它并不是执行一条delete语句而是把符合条件的数据先查找出来再一个个地执行delete操作
hibernate的二级缓存允许选用以下类型的缓存插件
EHCache可作为进程范围内的缓存存放数据的物理介质可以是内存或硬盘对hibernate的查询缓存提供了支持
OpenSymphony OSCache可作为进程范围内的缓存存放数据的物理介质可以是内存或硬盘提供了丰富的缓存数据过期策略对hibernate的查询缓存提供了支持
SwarmCache可作为群集范围内的缓存但不支持hibernate的查询缓存
JBossCache可作为群集范围内的缓存支持事务型并发访问策略对hibernate的查询缓存提供了支持
下表列出了以上四种类型的缓存插件支持的并发访问策略
以面的四种缓存插件都是由第三方提供的EHCache来自于hibernate开放源代码组织的另一个项目JBossCache由JBoss开放源代码组织提供为了把这些缓存插件集成到hibernate中hibernate提供了netsfhibernatecacheCacheProvider接口它是缓存插件与hibernate之间的适配器hibernate为以上缓存插件分别提供了内置的CacheProvider实现
netsfhibernatecacheEhCacheProvider
netsfhibernatecacheOSCacheProvider
netsfhibernatecacheSwarmCacheProvider
netsfhibernatecacheTreeCacheProviderJBossCache插件适配器
配置进程范围内的二级缓存主要包含以下步骤
选择需要使用二级缓存的持久化类设置它的命名缓存的并发访问策略hibernate既允许在分散的各个映射文件中为持久化类设置二级缓存还允许在hibernate的配置文件hibernatecfgxml中集中设置二级缓存后一种方式更有利于和缓存相关的配置代码的维护示例如下
<hibernateconfiguration>
<sessionfactory>
<property >
<! 设置JBossCache适配器 >
<property name=cacheprovider_class>netsfhibernatecacheTreeCacheProvider</property>
<property name=cacheuse_minimal_puts>true</property>
<mapping />
<! 设置Category类的二级缓存的并发访问策略 >
<classcache class=mypackCategory usage=transaction />
<! 设置Category类的items集合的二级缓存的并发访问策略 >
<collectioncache collection=ems usage=transactional />
<! 设置Item类的二级缓存的并发访问策略 >
<classcache class=mypackItem usage=transactional />
</sessionfactory>
</hibernateconfiguration>
cacheuse_minimal_puts属性为true表示hibernate会先检查对象是否己经存在于缓存中只有当对象不在缓存中才会向缓存加入该对象的散装数据默认为false对于群集范围的缓存如果读缓存的系统开销比写缓存的系统开销小可以将此属性设为true从而提高访问缓存的性能而对于进程范围内的缓存此属性应该取默认值false
选择合适的缓存插件每种插件都有自带的配置文件因此需要手工编辑该配置文件EHCache的配置文件为ehcachexml而JBossCache的配置文件为treecachexml在配置文件中需要为每个命名缓存设置数据过期策略
hibernate允许在类和集合的粒度上设置二级缓存在映射文件中<class>和<set>元素都有一个<cache>子元素这个子元素用来配置二级缓存例如以下代码把Category实例放入二级缓存中采用读写并发访问策略
<class name=mypackCategory talbe=CATEGORIES>
<cache usage=readwrite/>
<id >
</id>
</class>
每当应用程序从其它对象导航到Category对象或者从数据库中加载Category对象时hibernate就会把这个对象放到第二级缓存中<class>元素的<cache>子元素表明hibernate会缓存Category对象的简单属性的值但是它并不会同时缓存Category对象的集合属性如果希望缓存集合属性中的元素必须在<set>元素中加入<cache>子元素
<set name=items inverse=true lazy=true>
<cache usage=readwrite />
<key >
</set>
当应用程序调用categorygetItems(erate()方法时hibernate会把item集合中的元素存放到缓存中此时hibernate仅仅把与Category关联的Item对象的OID存放到缓存中如果希望把整个Item对象的散装数据存入缓存应该在Itemhbmxml文件的<class>元素中加入<cache>子元素
EHCache缓存插件是理想的进程范围内的缓存实现如果使用这种缓存插件需要在hibernate的hibernateproperties配置文件中指定EhCacheProvider适配器代码如下
hibernatecacheprovider=netsfhibernatecacheEhCacheProvider
EHCache缓存有自己的配置文件名为ehcachexml这个文件必须存放于应用的classpath中下面是一个样例
<ehcache>
<diskStore path=C:\\temp/>
<defaultCache maxElementsInMemory= eternal=false timeToIdleSeconds= timeToLiveSeconds= overflowToDisk=true/>
<cache name=mypackCategory maxElementsInMemory= eternal=true timeToIdleSeconds= timeToLiveSeconds= overflowToDisk=false/>
<cache name=ems maxElementsInMemory= eternal=false timeToIdleSeconds= timeToLiveSeconds= overflowToDisk=true/>
<cache name=mypackItem maxElementsInMemory= eternal=false timeToIdleSeconds= timeToLiveSeconds= overflowToDisk=true/>
</ehcache>
hibernate软件包的etc目录下提供了ehcachexml文件的样例并且对于它的配置元素做了详细的说明
ehcachexml目录下提供了ehcachexml文件的样例并且对它的配置元素做了详细的说明
<diskStore>指定一个文件目录当EHCache把数据写到硬盘上时将把数据写到这个文件目录下
<defaultCache>设定缓存的默认数据过期策略
<cache>设定具体的命名缓存的数据过期策略
在映射文件中对每个需要二级缓存的类和集合都做了单独的配置与此对应在ehcachexml文件中通过<cache>元素来为每个需要二级缓存的类和集合设定缓存的数据过期策略下面解释一下<cache>元素的各个属性的作用
name设置缓存的名字它的取值为类的完整名字或者类的集合的名字如果name属性为mypackCategory表示Category类的二级缓存如果name属性为ems表示Category类的items集合的二级缓存
maxInMemory设置基于内存的缓存可存放的对象的最大数目
eternal如果为true表示对象永远不会过期此时会忽略timeToIdleSeconds和timeToLiveSeconds属性默认为false
timeToIdleSeconds设定允许对象处于空闲状态的最长时间以秒为单位当对象从最近一次被访问后如果处于空闲状态的时间超过了指定的值这个对象会过期EHCache将把它从缓存中清除只有当eternal属性为false它才有效值为表示对象可以无限期地处于空闲状态
timeToLiveSeconds设定对象允许存在于缓存中的最长时间以秒为单位当对象自从被放入缓存中后如果处于缓存中的时间超过了指定的值这个对象就会过期EHCache将把它从缓存中清除只有当eternal属性为false它才有效值为表示对象可以无限期地处于空闲状态它的值必须大于或等于timeToIdleSeconds的值才有意义
overflowToDisk如果为true表示当基于内存的缓存中的对象数目达到了maxInMemory界限会把溢出的对象写到基于硬盘的缓存中
每个命名缓存代表一个缓存区域每个缓存区域有各自的数据过期策略命名缓存机制使得用户能够在每个类以及类的每个集合的粒度上设置数据过期策略
EHCache适用于hibernate应用发布在单个机器中的场合
在群集环境下可以用JBossCache作为hibernate的二级缓存它的配置步骤如下
在hibernate配置文件中设置JBossCache适配器并且为需要使用二级缓存的类和集合设置缓存的并发访问策略
编辑JBossCache自身的配置文件名为treecachexml这个文件必须放在classpath中对于群集环境中的每个节点都必须提供单独的treecachexml文件假如群集环境中有两个节点node A和node Bnode A节点的名字为ClusterA下面是node A节点的treecachexml文件的样例
<?xml version= encoding=UTF?>
<server>
<classpath codebase=/lib archives=jbosscachejarjgroupsjar/>
<! 把TreeCache发布为JBoss的一个JMX服务 >
<mbean code=orgjbosscacheTreeCache name=jbosscache:service=TreeCache>
<depends>jboss:service=Naming</depends>
<depends>jboss:service=TransactionManager</depends>
<! TreeCache运行在群集环境的名为ClusterA的节点上 >
<attribute name=ClusterName>ClusterA</attribute>
<! TreeCache采用同步通信机制 >
<attribute name=CacheMode>REPL_SYNC</attribute>
<attribute name=SyncReplTimeout></attribute>
<attribute name=LockAcquisitionTimeout></attribute>
<attribute name=FetchStateOnStartup>true</attribute>
<! TreeCache采用内置的数据过期策略LRUPolicy >
<attribute name=EvictionPolicyClass>orgjbosscacheevictionLRUPolicy</attribute>
<attribute name=EvictionPolicyConfig>
<config>
<attribute name=wakeUpIntervalSeconds></attribute>
<! Cache wide default >
<region name=/_default_>
<attribute name=maxNodes></attribute>
<attribute name=timeToIdleSeconds></attribute>
</region>
<! 配置Category类的数据过期策略 >
<region name=/mypack/Category>
<attribute name=maxNodes></attribute>
<attribute name=timeToIdleSeconds></attribute>
</region>
<! 配置Category类的items集合的数据过期策略 >
<region name=/mypack/Category/items>
<attribute name=maxNodes></attribute>
<attribute name=timeToIdleSeconds></attribute>
</region>
</config>
</attribute>
<! 配置JGroup >
<attribute name=ClusterConfig>
<config>
<UDP bind_addr= ip_mcast=true loopback=false />
<PING timeout= num_initial_members= up_thread=false down_thread=false />
<FD_SOCK/>
<pbcastNAKACK gc_lag= retransmit_timeout= max_xmit_size= up_thread=false down_thread=false />
<UNICAST timeout= window_size= min_threshold= down_thread=false />
<pbcastSTABLE desired_avg_gossip= up_thread=false down_thread=false />
<FRAG frag_size= down_thread=false up_thread=false />
<pbcastGMS join_timeout= join_retry_timeout= shun=true print_local_addr=true />
<pbcastSTATE_TRANSFER up_thread=true down_thread=true />
</config>
</attribute>
</mbean>
</server>
以上配置文件把JBossCache配置为JBoss的一个JMX服务此外还配置了JGroup它是一个通信库JBoss为JBossCache提供了几种实现hibernate采用的是TreeCache实现treecachexml文件夹的开头几行是JBoss的JMX服务的发布描述符如果TreeCache不运行在JBoss服务器中这几行会被忽略
TreeCache采用内置的orgjbosscacheevictionLRUPolicy策略它是一种控制缓存中的数据过期的策略由于当一个对象过期后就会从缓存中清除因此数据过期策略也叫做数据清除策略接下来配置了Category类和它的items集合设置了具体的数据过期策略
最后配置了JGroup它包含一系列通信协议这些通信协议的次序很重要不能随意修改它们第一个协议为UDP它和一个IP地址绑定这是当前节点的IP地址UDP协议使得该节点支持广播通信如果节点选用的是微软的windows平台必须把loopback属性设为true其它的JGroup属性很复杂它们主要用于管理群集中节点之间的通信想进一步了解可以参考JBoss网站上的JGroup文档
可以按照同样的方式配置node B节点的treecachexml文件只需修改其中UDP协议的IP绑定地址
通过以上配置hibernate将启用群集范围内的事务型缓存每当一个新的元素加入到一个节点的缓存中时这个元素就会被复制到其它节点的缓存中如果缓存中的一个元素被更新那么它就会过期并从缓存中清除
只有在hibernate的配置文件或映射文件中为一个持久化类设置了二级缓存hibernate在加载这个类的实例时才会启用二级缓存
SessionFactory也提供了evict()方法用于从二级缓存中清除对象的散装数据如
sessionFactoryevict(Categoryclass );//清除二级缓存中OID为的Category对象
sessionFactoryevict(mypackCategory);//清除二级缓存中所有的Category对象
sessionFactoryevictCollection(ems);//清除二级缓存中Category类的所有对象的items集合
下面是比较hibernate的一级缓存和二级缓存