hibernate二级缓存,什么是hibernate中的二级缓存
hibernate二级缓存,什么是hibernate中的二级缓存详细介绍
本文目录一览: Hibernate二级缓存的作用是什么?
Hibernate中应用缓存:因为应用程序访问数据库,读写数据的代价非常高,而利用持久层的缓存可以减少应用程序与数据库之间的交互,即把访问过的数据保存到缓存中,应用程序再次访问已经访问过的数据,这些数据就可以从缓存中获取,而不必再从数据库中获取。
同时如果数据库中的数据被修改或者删除,那么是、该数据所对应的缓存数据,也会被同步修改或删除,进而保持缓存数据的一致性。 Hibernate的二级缓存由SessionFactory对象管理,是应用级别的缓存。它可以缓存整个应用的持久化对象,所以又称为“SessionFactory缓存”。
Hibernate中提供了两级Cache,第一级别的缓存是Session级别的缓存,它是属于事务范围的缓存。这一级别的缓存由hibernate管理的,一般情况下无需进行干预;第二级别的缓存是SessionFactory级别的缓存,它是属于进程范围或群集范围的缓存。这一级别的缓存可以进行配置和更改,并且可以动态加载和卸载。 Hibernate还为查询结果提供了一个查询缓存,它依赖于第二级缓存。
使用缓存,是需要对应用系统进行性能优化而常采用的一种重要手段。合理地运用缓存,可以极大的提高应用系统的运行效率。
hibernate二级缓存中的缓存对象可以被整个应用的Session对象共享,即使关闭当前Session对象,新建的Session对象仍可使用。使用Hibernate的二级缓存之后查询数据,Session对象会首先在以及缓存中查找有无缓存数据被命中。如果没有,则查找二级缓存。如果有,则直接返回所命中的数据;否则查询数据库。
Hibernate的一级缓存与二级缓存的区别?
一级缓存就是Session级别的缓存,一个Session做了一个查询操作,它会把这个操作的结果放在一级缓存中,如果短时间内这个session(一定要同一个session)又做了同一个操作,那么hibernate直接从一级缓存中拿,而不会再去连数据库,取数据。
二级缓存就是SessionFactory级别的缓存,顾名思义,就是查询的时候会把查询结果缓存到二级缓存中,如果同一个sessionFactory创建的某个session执行了相同的操作,hibernate就会从二级缓存中拿结果,而不会再去连接数据库。
缓存是介于应用程序和物理数据源之间,其作用是为了降低应用程序对物理数据源访问的频次,从而提高了应用的运行性能。缓存内的数据是对物理数据源中的数据的复制,应用程序在运行时从缓存读写数据,在特定的时刻或事件会同步缓存和物理数据源的数据。
缓存的介质一般是内存,所以读写速度很快。但如果缓存中存放的数据量非常大时,也会用硬盘作为缓存介质。缓存的实现不仅仅要考虑存储的介质,还要考虑到管理缓存的并发访问和缓存数据的生命周期。
Hibernate缓存机制
缓存是位于应用程序与物理数据源之间 用于临时存放复制数据的内存区域 目的是为了减少应用程序对物理数据源访问的次数 从而提高应用程序的运行性能
Hibernate在查询数据时 首先到缓存中去查找 如果找到就直接使用 找不到的时候就会从物理数据源中检索 所以 把频繁使用的数据加载到缓存区后 就可以大大减少应用程序对物理数据源的访问 使得程序的运行性能明显的提升
Hibernate缓存分类
Session缓存 一级缓存
SessionFactory的缓存分为内置缓存和外置缓存 内置缓存中存放的是SessionFactory对象的一些集合属性包含的数据(映射元素据及预定义SQL语句等) 对于应用程序来说 它是只读的 外置缓存中存放的是数据库数据的副本 其作用和一级缓存类似 二级缓存除了以内存作为存储介质外 还可以选用硬盘等外部存储设备
Hibernate的缓存范围
Hibernate的一级缓存和二级缓存都位于均位于持久层 且均用于存放数据库数据的副本 最大的区别就是缓存的范围各不一样
缓存的范围分为 类:
事务范围
事务范围的缓存只能被当前事务访问 每个事务都有各自的缓存 缓存内的数据通常采用相互关联的对象形式 缓存的生命周期依赖于事务的生命周期 只有当事务结束时 缓存的生命周期才会结束 事务范围的缓存使用内存作为存储介质 一级缓存就属于事务范围
应用范围
应用程序的缓存可以被应用范围内的所有事务共享访问 缓存的生命周期依赖于应用的生命周期 只有当应用结束时 缓存的生命周期才会结束 应用范围的缓存可以使用内存或硬盘作为存储介质 二级缓存就属于应用范围
集群范围
在集群环境中 缓存被一个机器或多个机器的进程共享 缓存中的数据被复制到集群环境中的每个进程节点 进程间通过远程通信来保证缓存中的数据的一致 缓存中的数据通常采用对象的松散数据形式
Hibernate的缓存管理
一级缓存的管理:
evit(Object obj) 将指定的持久化对象从一级缓存中清除 释放对象所占用的内存资源 指定对象从持久化状态变为脱管状态 从而成为游离对象
clear() 将一级缓存中的所有持久化对象清除 释放其占用的内存资源
contains(Object obj) 判断指定的对象是否存在于一级缓存中
flush() 刷新一级缓存区的内容 使之与数据库数据保持同步
二级缓存的管理:
evict(Class arg Serializable arg ) 将某个类的指定ID的持久化对象从二级缓存中清除 释放对象所占用的资源
Java代码
sessionFactory evict(Customer class new Integer( ));
evict(Class arg ) 将指定类的所有持久化对象从二级缓存中清除 释放其占用的内存资源
Java代码
sessionFactory evict(Customer class);
evictCollection(String arg ) 将指定类的所有持久化对象的指定集合从二级缓存中清除 释放其占用的内存资源
Java代码
sessionFactory evictCollection( Customer orders );
Hibernate的二级缓存的配置
首先 不是所有的数据都适合放在二级缓存中 看一下 什么样的数据适合放在二级缓存中来?什么样的数据不适合放在二级缓存中来?
下面这几种情况就不适合加载到二级缓存中:
经常被修改的数据
绝对不允许出现并发访问的数据
与其他应用共享的数据
下面这己种情况合适加载到二级缓存中:
数据更新频率低
允许偶尔出现并发问题的非重要数据
不会被并发访问的数据
常量数据
不会被第三方修改的数据
Hibernate的二级缓存功能是靠配置二级缓存插件来实现的 Hibernate为了集成这些插件 Hibernate提供了 hibernate cache CacheProvider借口 它充当缓存插件与Hibernate之间的适配器
常用的二级缓存插件
EHCache hibernate cache EhCacheProvider
OSCache hibernate cache OSCacheProvider
SwarmCahe hibernate cache SwarmCacheProvider
JBossCache hibernate cache TreeCacheProvider
简单介绍一下EHCache的配置
hibernate cfg xml
Xml代码
hibernate cache EhCacheProvider
true
ehcache xml
Xml代码
**** hbm xml
Xml代码
//Hibernate/Hibernate Mapping DTD //EN
mapping dtd >
lishixinzhi/Article/program/Java/ky/201311/28418
Hibernate缓存何时使用和如何使用
关于hibernate缓存的问题 基本的缓存原理
Hibernate缓存分为二级
第一级存放于session中称为一级缓存 默认带有且不能卸载
第二级是由sessionFactory控制的进程级缓存 是全局共享的缓存 凡是会调用二级缓存的查询方法 都会从中受益 只有经正确的配置后二级缓存才会发挥作用 同时在进行条件查询时必须使用相应的方法才能从缓存中获取数据 比如erate()方法 load get方法等 必须注意的是session find方法永远是从数据库中获取数据 不会从二级缓存中获取数据 即便其中有其所需要的数据也是如此
查询时使用缓存的实现过程为 首先查询一级缓存中是否具有需要的数据 如果没有 查询二级缓存 如果二级缓存中也没有 此时再执行查询数据库的工作 要注意的是 此 种方式的查询速度是依次降低的
存在的问题
一级缓存的问题以及使用二级缓存的原因
因为Session的生命期往往很短 存在于Session内部的第一级最快缓存的生命期当然也很短 所以第一级缓存的命中率是很低的 其对系统性能的改善也是很有限的 当然 这个Session内部缓存的主要作用是保持Session内部数据状态同步 并非是hibernate为了大幅提高系统性能所提供的
为了提高使用hibernate的性能 除了常规的一些需要注意的方法比如
使用延迟加载 迫切外连接 查询过滤等以外 还需要配置hibernate的二级缓存 其对系统整体性能的改善往往具有立竿见影的效果!
(经过自己以前作项目的经验 一般会有 ~ 倍的性能提高)
N+ 次查询的问题
什么时候会遇到 +N的问题?
前提 Hibernate默认表与表的关联方法是fetch= select 不是fetch= join 这都是为了懒加载而准备的
)一对多(
) 在 的这方 通过 条sql查找得到了 个对象 由于关联的存在 那么又需要将这个对象关联的集合取出 所以合集数量是n还要发出n条sql 于是本来的 条sql查询变成了 +n条
)多对一
在多的这方 通过 条sql查询得到了n个对象 由于关联的存在 也会将这n个对象对应的 方的对象取出 于是本来的 条sql查询变成了 +n条
)iterator 查询时 一定先去缓存中找( 条sql查集合 只查出ID) 在没命中时 会再按ID到库中逐一查找 产生 +n条SQL
怎么解决 +N 问题?
)lazy=true hibernate 开始已经默认是lazy=true了 lazy=true时不会立刻查询关联对象 只有当需要关联对象(访问其属性 非id字段)时才会发生查询动作
)使用二级缓存 二级缓存的应用将不怕 +N 问题 因为即使第一次查询很慢(未命中) 以后查询直接缓存命中也是很快的 刚好又利用了 +N
) 当然你也可以设定fetch= join 一次关联表全查出来 但失去了懒加载的特性
执行条件查询时 iterate()方法具有著名的 n+ 次查询的问题 也就是说在第一次查询时iterate方法会执行满足条件的查询结果数再加一次(n+ )的查询 但是此问题只存在于第一次查询时 在后面执行相同查询时性能会得到极大的改善 此方法适合于查询数据量较大的业务数据
但是注意 当数据量特别大时(比如流水线数据等)需要针对此持久化对象配置其具体的缓存策略 比如设置其存在于缓存中的最大记录数 缓存存在的时间等参数 以避免系统将大量的数据同时装载入内存中引起内存资源的迅速耗尽 反而降低系统的性能!!!
使用hibernate二级缓存的其他注意事项
关于数据的有效性
另外 hibernate会自行维护二级缓存中的数据 以保证缓存中的数据和数据库中的真实数据的一致性!无论何时 当你调用save() update()或 saveOrUpdate()方法传递一个对象时 或使用load() get() list() iterate() 或scroll()方法获得一个对象时 该对象都将被加入到Session的内部缓存中 当随后flush()方法被调用时 对象的状态会和数据库取得同步
也就是说删除 更新 增加数据的时候 同时更新缓存 当然这也包括二级缓存!
只要是调用hibernate API执行数据库相关的工作 hibernate都会为你自动保证 缓存数据的有效性!!
但是 如果你使用了JDBC绕过hibernate直接执行对数据库的操作 此时 Hibernate不会/也不可能自行感知到数据库被进行的变化改动 也就不能再保证缓存中数据的有效性!!
这也是所有的ORM产品共同具有的问题 幸运的是 Hibernate为我们暴露了Cache的清除方法 这给我们提供了一个手动保证数据有效性的机会!!
一级缓存 二级缓存都有相应的清除方法
其中二级缓存提供的清除方法为
按对象class清空缓存
按对象class和对象的主键id清空缓存
清空对象的集合中的缓存数据等
适合使用的情况
并非所有的情况都适合于使用二级缓存 需要根据具体情况来决定 同时可以针对某一个持久化对象配置其具体的缓存策略
适合于使用二级缓存的情况
数据不会被第三方修改
一般情况下 会被hibernate以外修改的数据最好不要配置二级缓存 以免引起不一致的数据 但是如果此数据因为性能的原因需要被缓存 同时又有可能被第 方比如SQL修改 也可以为其配置二级缓存 只是此时需要在sql执行修改后手动调用cache的清除方法 以保证数据的一致性
数据大小在可接收范围之内
如果数据表数据量特别巨大 此时不适合于二级缓存 原因是缓存的数据量过大可能会引起内存资源紧张 反而降低性能 如果数据表数据量特别巨大 但是经常使用的往往只是较新的那部分数据 此时 也可为其配置二级缓存 但是必须单独配置其持久化类的缓存策略 比如最大缓存数 缓存过期时间等 将这些参数降低至一个合理的范围(太高会引起内存资源紧张 太低了缓存的意义不大)
数据更新频率低
对于数据更新频率过高的数据 频繁同步缓存中数据的代价可能和 查询缓存中的数据从中获得的好处相当 坏处益处相抵消 此时缓存的意义也不大
非关键数据(不是财务数据等)
财务数据等是非常重要的数据 绝对不允许出现或使用无效的数据 所以此时为了安全起见最好不要使用二级缓存
因为此时 正确性 的重要性远远大于 高性能 的重要性
目前系统中使用hibernate缓存的建议
目前情况
一般系统中有三种情况会绕开hibernate执行数据库操作
多个应用系统同时访问一个数据库
此种情况使用hibernate二级缓存会不可避免的造成数据不一致的问题 此时要进行详细的设计 比如在设计上避免对同一数据表的同时的写入操作 使用数据库各种级别的锁定机制等
动态表相关
所谓 动态表 是指在系统运行时根据用户的操作系统自动建立的数据表
比如 自定义表单 等属于用户自定义扩展开发性质的功能模块 因为此时数据表是运行时建立的 所以不能进行hibernate的映射 因此对它的操作只能是绕开hibernate的直接数据库JDBC操作
如果此时动态表中的数据没有设计缓存 就不存在数据不一致的问题
如果此时自行设计了缓存机制 则调用自己的缓存同步方法即可
使用sql对hibernate持久化对象表进行批量删除时
此时执行批量删除后 缓存中会存在已被删除的数据
分析
当执行了第 条(sql批量删除)后 后续的查询只可能是以下三种方式
a session find()方法
根据前面的总结 find方法不会查询二级缓存的数据 而是直接查询数据库
所以不存在数据有效性的问题
b 调用iterate方法执行条件查询时
根据iterate查询方法的执行方式 其每次都会到数据库中查询满足条件的id值 然后再根据此id 到缓存中获取数据 当缓存中没有此id的数据才会执行数据库查询
如果此记录已被sql直接删除 则iterate在执行id查询时不会将此id查询出来 所以 即便缓存中有此条记录也不会被客户获得 也就不存在不一致的情况 (此情况经过测试验证)
c 用get或load方法按id执行查询
客观上此时会查询得到已过期的数据 但是又因为系统中执行sql批量删除一般是针对中间关联数据表 对于中间关联表的查询一般都是采用条件查询 按id来查询某一条关联关系的几率很低 所以此问题也不存在!
如果某个值对象确实需要按id查询一条关联关系 同时又因为数据量大使用 了sql执行批量删除 当满足此两个条件时 为了保证按id 的查询得到正确的结果 可以使用手动清楚二级缓存中此对象的数据的方法!!(此种情况出现的可能性较小)
建 议
建议不要使用sql直接执行数据持久化对象的数据的更新 但是可以执行 批量删除 (系统中需要批量更新的地方也较少)
如果必须使用sql执行数据的更新 必须清空此对象的缓存数据 调用
SessionFactory evict(class)
SessionFactory evict(class id)等方法
在批量删除数据量不大的时候可以直接采用hibernate的批量删除 这样就不存在绕开hibernate执行sql产生的缓存数据一致性的问题
不推荐采用hibernate的批量删除方法来删除大批量的记录数据
原因是hibernate的批量删除会执行 条查询语句外加 满足条件的n条删除语句 而不是一次执行一条条件删除语句!!当待删除的数据很多时会有很大的性能瓶颈!!!如果批量删除数据量较大 比如超过 条 可以采用JDBC直接删除 这样作的好处是只执行一条sql删除语句 性能会有很大的改善 同时 缓存数据同步的问题 可以采用 hibernate清除二级缓存中的相关数据的方法
调 用
SessionFactory evict(class) ;
SessionFactory evict(class id)等方法
所以说 对于一般的应用系统开发而言(不涉及到集群 分布式数据同步问题等) 因为只在中间关联表执行批量删除时调用了sql执行 同时中间关联表一般是执行条件查询不太可能执行按id查询 所以 此时可以直接执行sql删除 甚至不需要调用缓存的清除方法 这样做不会导致以后配置了二级缓存引起数据有效性的问题
退一步说 即使以后真的调用了按id查询中间表对象的方法 也可以通过调用清除缓存的方法来解决
具体的配置方法
根据我了解的很多hibernate的使用者在调用其相应方法时都迷信的相信 hibernate会自行为我们处理性能的问题 或者 hibernate 会自动为我们的所有操作调用缓存 实际的情况是hibernate虽然为我们提供了很好的缓存机制和扩展缓存框架的支持 但是必须经过正确的调用其才有可能发挥作用!!所以造成很多使用hibernate的系统的性能问题 实际上并不是hibernate不行或者不好 而是因为使用者没有正确的了解其使用方法造成的 相反 如果配置得当hibernate的性能表现会让你有相当 惊喜的 发现 下面我讲解具体的配置方法
ibernate提供了二级缓存的接口
net sf hibernate cache Provider
同时提供了一个默认的 实现net sf hibernate cache HashtableCacheProvider
也可以配置 其他的实现 比如ehcache jbosscache等
具体的配置位置位于hibernate cfg xml文件中
true
net sf hibernate cache HashtableCacheProvider
很多的hibernate使用者在 配置到 这一步 就以为 完事了
注意 其实光这样配 根本就没有使用hibernate的二级缓存 同时因为他们在使用hibernate时大多时候是马上关闭session 所以 一级缓存也没有起到任何作用 结果就是没有使用任何缓存 所有的hibernate操作都是直接操作的数据库!!性能可以想见
正确的办法是除了以上的配置外还应该配置每一个vo对象的具体缓存策略 在影射文件中配置 例如
关键就是这个
其有几个选择read only read write transactional 等
然后在执行查询时 注意了 如果是条件查询 或者返回所有结果的查询 此时session find()方法 不会获取缓存中的数据 只有调用erate()方法时才会调缓存的数据
同时 get 和 load方法 是都会查询缓存中的数据
对于不同的缓存框架具体的配置方法会有不同 但是大体是以上的配置(另外 对于支持事务型 以及支持集群的环境的配置我会争取在后续的文章中中 发表出来)
lishixinzhi/Article/program/Java/ky/201311/28715
什么是hibernate中的二级缓存
缓存是介于应用程序和物理数据源之间,其作用是为了降低应用程序对物理数据源访问的频次,从而提高了应用的运行性能。缓存内的数据是对物理数据源中的数据的复制,应用程序在运行时从缓存读写数据,在特定的时刻或事件会同步缓存和物理数据源的数据。
缓存的介质一般是内存,所以读写速度很快。但如果缓存中存放的数据量非常大时,也会用硬盘作为缓存介质。缓存的实现不仅仅要考虑存储的介质,还要考虑到管理缓存的并发访问和缓存数据的生命周期。
Hibernate的缓存包括Session的缓存和SessionFactory的缓存,其中SessionFactory的缓存又可以分为两类:内置缓存和外置缓存。Session的缓存是内置的,不能被卸载,也被称为Hibernate的第一级缓存。SessionFactory的内置缓存和Session的缓存在实现方式上比较相似,前者是SessionFactory对象的一些集合属性包含的数据,后者是指Session的一些集合属性包含的数据。SessionFactory的内置缓存中存放了映射元数据和预定义SQL语句,映射元数据是映射文件中数据的拷贝,而预定义SQL语句是在Hibernate初始化阶段根据映射元数据推导出来,SessionFactory的内置缓存是只读的,应用程序不能修改缓存中的映射元数据和预定义SQL语句,因此SessionFactory不需要进行内置缓存与映射文件的同步。SessionFactory的外置缓存是一个可配置的插件。在默认情况下,SessionFactory不会启用这个插件。外置缓存的数据是数据库数据的拷贝,外置缓存的介质可以是内存或者硬盘。SessionFactory的外置缓存也被称为Hibernate的第二级缓存。
Hibernate的这两级缓存都位于持久化层,存放的都是数据库数据的拷贝,那么它们之间的区别是什么呢?为了理解二者的区别,需要深入理解持久化层的缓存的两个特性:缓存的范围和缓存的并发访问策略。
持久化层的缓存的范围
缓存的范围决定了缓存的生命周期以及可以被谁访问。缓存的范围分为三类。
1 事务范围:缓存只能被当前事务访问。缓存的生命周期依赖于事务的生命周期,当事务结束时,缓存也就结束生命周期。在此范围下,缓存的介质是内存。事务可以是数据库事务或者应用事务,每个事务都有独自的缓存,缓存内的数据通常采用相互关联的的对象形式。
2 进程范围:缓存被进程内的所有事务共享。这些事务有可能是并发访问缓存,因此必须对缓存采取必要的事务隔离机制。缓存的生命周期依赖于进程的生命周期,进程结束时,缓存也就结束了生命周期。进程范围的缓存可能会存放大量的数据,所以存放的介质可以是内存或硬盘。缓存内的数据既可以是相互关联的对象形式也可以是对象的松散数据形式。松散的对象数据形式有点类似于对象的序列化数据,但是对象分解为松散的算法比对象序列化的算法要求更快。
3 集群范围:在集群环境中,缓存被一个机器或者多个机器的进程共享。缓存中的数据被复制到集群环境中的每个进程节点,进程间通过远程通信来保证缓存中的数据的一致性,缓存中的数据通常采用对象的松散数据形式。
对大多数应用来说,应该慎重地考虑是否需要使用集群范围的缓存,因为访问的速度不一定会比直接访问数据库数据的速度快多少。
持久化层可以提供多种范围的缓存。如果在事务范围的缓存中没有查到相应的数据,还可以到进程范围或集群范围的缓存内查询,如果还是没有查到,那么只有到数据库中查询。事务范围的缓存是持久化层的第一级缓存,通常它是必需的;进程范围或集群范围的缓存是持久化层的第二级缓存,通常是可选的。
持久化层的缓存的并发访问策略
当多个并发的事务同时访问持久化层的缓存的相同数据时,会引起并发问题,必须采用必要的事务隔离措施。
在进程范围或集群范围的缓存,即第二级缓存,会出现并发问题。因此可以设定以下四种类型的并发访问策略,每一种策略对应一种事务隔离级别。
事务型:仅仅在受管理环境中适用。它提供了Repeatable Read事务隔离级别。对于经常被读但很少修改的数据,可以采用这种隔离类型,因为它可以防止脏读和不可重复读这类的并发问题。
读写型:提供了Read Committed事务隔离级别。仅仅在非集群的环境中适用。对于经常被读但很少修改的数据,可以采用这种隔离类型,因为它可以防止脏读这类的并发问题。
非严格读写型:不保证缓存与数据库中数据的一致性。如果存在两个事务同时访问缓存中相同数据的可能,必须为该数据配置一个很短的数据过期时间,从而尽量避免脏读。对于极少被修改,并且允许偶尔脏读的数据,可以采用这种并发访问策略。
只读型:对于从来不会修改的数据,如参考数据,可以使用这种并发访问策略。
事务型并发访问策略是事务隔离级别最高,只读型的隔离级别最低。事务隔离级别越高,并发性能就越低。
什么样的数据适合存放到第二级缓存中?
1 很少被修改的数据
2 不是很重要的数据,允许出现偶尔并发的数据
3 不会被并发访问的数据
4 参考数据
不适合存放到第二级缓存的数据?
1 经常被修改的数据
2 财务数据,绝对不允许出现并发
3 与其他应用共享的数据。
Hibernate的二级缓存
如前所述,Hibernate提供了两级缓存,第一级是Session的缓存。由于Session对象的生命周期通常对应一个数据库事务或者一个应用事务,因此它的缓存是事务范围的缓存。第一级缓存是必需的,不允许而且事实上也无法比卸除。在第一级缓存中,持久化类的每个实例都具有唯一的OID。
第二级缓存是一个可插拔的的缓存插件,它是由SessionFactory负责管理。由于SessionFactory对象的生命周期和应用程序的整个过程对应,因此第二级缓存是进程范围或者集群范围的缓存。这个缓存中存放的对象的松散数据。第二级对象有可能出现并发问题,因此需要采用适当的并发访问策略,该策略为被缓存的数据提供了事务隔离级别。缓存适配器用于把具体的缓存实现软件与Hibernate集成。第二级缓存是可选的,可以在每个类或每个集合的粒度上配置第二级缓存。
Hibernate的二级缓存策略的一般过程如下:
1) 条件查询的时候,总是发出一条select * from table_name where …. (选择所有字段)这样的SQL语句查询数据库,一次获得所有的数据对象。
2) 把获得的所有数据对象根据ID放入到第二级缓存中。
3) 当Hibernate根据ID访问数据对象的时候,首先从Session一级缓存中查;查不到,如果配置了二级缓存,那么从二级缓存中查;查不到,再查询数据库,把结果按照ID放入到缓存。
4) 删除、更新、增加数据的时候,同时更新缓存。
Hibernate的二级缓存策略,是针对于ID查询的缓存策略,对于条件查询则毫无作用。为此,Hibernate提供了针对条件查询的Query缓存。
Hibernate的Query缓存策略的过程如下:
1) Hibernate首先根据这些信息组成一个Query Key,Query Key包括条件查询的请求一般信息:SQL, SQL需要的参数,记录范围(起始位置rowStart,最大记录个数maxRows),等。
2) Hibernate根据这个Query Key到Query缓存中查找对应的结果列表。如果存在,那么返回这个结果列表;如果不存在,查询数据库,获取结果列表,把整个结果列表根据Query Key放入到Query缓存中。
3) Query Key中的SQL涉及到一些表名,如果这些表的任何数据发生修改、删除、增加等操作,这些相关的Query Key都要从缓存中清空。
第一级缓存是Session的缓存.
二级缓存是进程范围或群集范围的缓存,也就是SessionFactory的外置缓存
第一级别的缓存是Session级别的缓存,是属于事务范围的缓存,由Hibernate管理,一般无需进行干预。第二级别的缓存是SessionFactory级别的缓存,是属于进程范围的缓存。
二级缓存也分为了两种
内置缓存:Hibernate自带的,不可卸载,通常在Hibernate的初始化阶段,Hibernate会把映射元数据和预定义的SQL语句放置到SessionFactory的缓存中。该内置缓存是只读的。
外置缓存:通常说的二级缓存也就是外置缓存,在默认情况下SessionFactory不会启用这个缓存插件,外置缓存中的数据是数据库数据的复制,外置缓存的物理介质可以是内存或者硬盘。
hibernate二级缓存的结构
2.并发访问策略
transactional
(事务型)
仅在受管理的环境中适用
提供Repeatable Read事务隔离级别
适用经常被读,很少修改的数据
可以防止脏读和不可重复读的并发问题
缓存支持事务,发生异常的时候,缓存也能够回滚
read-write
(读写型)
提供Read Committed事务隔离级别
在非集群的环境中适用
适用经常被读,很少修改的数据
可以防止脏读
更新缓存的时候会锁定缓存中的数据
nonstrict-read-write
(非严格读写型)
适用极少被修改,偶尔允许脏读的数据(两个事务同时修改数据的情况很少见)
不保证缓存和数据库中数据的一致性
为缓存数据设置很短的过期时间,从而尽量避免脏读
不锁定缓存中的数据
read-only
(只读型)
适用从来不会被修改的数据(如参考数据)
在此模式下,如果对数据进行更新操作,会有异常
事务隔离级别低,并发性能高
在集群环境中也能完美运作
分析:通过上述表格分析如下
适合放入二级缓存中数据
很少被修改
不是很重要的数据,允许出现偶尔的并发问题
不适合放入二级缓存中的数据
经常被修改
财务数据,绝对不允许出现并发问题
与其他应用数据共享的数据
java里hibernate的一、二级缓存是怎么回事?
一级缓存是session,二级缓存是SessionFactory。二级缓存分为对象缓存和查询缓存(内置和外置缓存)。用的时候,要在hibernate里设置,怎么设的不会。。。。应该就问这么多。查询缓存就是预定义的sql语句。
java里hibernate的一、二级缓存:
1.第一级是Session的缓存。由于Session对象的生命周期通常对应一个数据库事务或者一个应用事务,因此它的缓存是事务范围的缓存。第一级缓存是必需的,不允许而且事实上也无法比卸除。在第一级缓存中,持久化类的每个实例都具有唯一的OID。
2.第二级缓存是一个可插拔的的缓存插件,它是由SessionFactory负责管理。由于SessionFactory对象的生命周期和应用程序的整个过程对应,因此第二级缓存是进程范围或者集群范围的缓存。这个缓存中存放的对象的松散数据。第二级对象有可能出现并发问题,因此需要采用适当的并发访问策略,该策略为被缓存的数据提供了事务隔离级别。缓存适配器用于把具体的缓存实现软件与Hibernate集成。
Hibernate的一级缓存与二级缓存的区别?
一级缓存就是Session级别的缓存,一个Session做了一个查询操作,它会把这个操作的结果放在一级缓存中,如果短时间内这个session(一定要同一个session)又做了同一个操作,那么hibernate直接从一级缓存中拿,而不会再去连数据库,取数据。
二级缓存就是SessionFactory级别的缓存,顾名思义,就是查询的时候会把查询结果缓存到二级缓存中,如果同一个sessionFactory创建的某个session执行了相同的操作,hibernate就会从二级缓存中拿结果,而不会再去连接数据库。
纯手打,希望能帮到你
一级缓存就是Session级别的缓存,一个Session做了一个查询操作,它会把这个操作的结果放在一级缓存中,如果短时间内这个session(一定要同一个session)又做了同一个操作,那么hibernate直接从一级缓存中拿,而不会再去连数据库,取数据。
二级缓存就是SessionFactory级别的缓存,顾名思义,就是查询的时候会把查询结果缓存到二级缓存中,如果同一个sessionFactory创建的某个session执行了相同的操作,hibernate就会从二级缓存中拿结果,而不会再去连接数据库。
缓存是介于应用程序和物理数据源之间,其作用是为了降低应用程序对物理数据源访问的频次,从而提高了应用的运行性能。缓存内的数据是对物理数据源中的数据的复制,应用程序在运行时从缓存读写数据,在特定的时刻或事件会同步缓存和物理数据源的数据。
缓存的介质一般是内存,所以读写速度很快。但如果缓存中存放的数据量非常大时,也会用硬盘作为缓存介质。缓存的实现不仅仅要考虑存储的介质,还要考虑到管理缓存的并发访问和缓存数据的生命周期。
在向大家详细介绍Hibernate二级缓存之前,首先让大家了解下一级缓存,然后全面介绍Hibernate二级缓存。
Hibernate中提供了两级Cache,第一级别的缓存是Session级别的缓存,它是属于事务范围的缓存。这一级别的缓存由hibernate管理的,一般情况下无需进行干预;第二级别的缓存是SessionFactory级别的缓存,它是属于进程范围或群集范围的缓存。这一级别的缓存可以进行配置和更改,并且可以动态加载和卸载。 Hibernate还为查询结果提供了一个查询缓存,它依赖于第二级缓存。
一. 一级缓存和二级缓存的比较:
第一级缓存 第二级缓存 存放数据的形式相互关联的持久化对象 对象的散装数据 缓存的范围事务范围,每个事务都有单独的第一级缓存进程范围或集群范围,缓存被同一个进程或集群范围内的所有事务共享并发访问策略由于每个事务都拥有单独的第一级缓存,不会出现并发问题,无需提供并发访问策略由于多个事务会同时访问第二级缓存中相同数据,因此必须提供适当的并发访问策略,来保证特定的事务隔离级别数据过期策略没有提供数据过期策略。处于一级缓存中的对象永远不会过期,除非应用程序显式清空缓存或者清除特定的对象必须提供数据过期策略,如基于内存的缓存中的对象的最大数目,允许对象处于缓存中的最长时间,以及允许对象处于缓存中的最长空闲时间物理存储介质内存内存和硬盘。对象的散装数据首先存放在基于内存的缓存中,当内存中对象的数目达到数据过期策略中指定上限时,就会把其余的对象写入基于硬盘的缓存中。缓存的软件实现在Hibernate的Session的实现中包含了缓存的实现由第三方提供,Hibernate仅提供了缓存适配器(CacheProvider)。用于把特定的缓存插件集成到Hibernate中。启用缓存的方式只要应用程序通过Session接口来执行保存、更新、删除、加载和查询数据库数据的操作,Hibernate就会启用第一级缓存,把数据库中的数据以对象的形式拷贝到缓存中,对于批量更新和批量删除操作,如果不希望启用第一级缓存,可以绕过Hibernate API,直接通过JDBC API来执行指操作。用户可以在单个类或类的单个集合的粒度上配置第二级缓存。如果类的实例被经常读但很少被修改,就可以考虑使用第二级缓存。只有为某个类或集合配置了第二级缓存,Hibernate在运行时才会把它的实例加入到第二级缓存中。用户管理缓存的方式第一级缓存的物理介质为内存,由于内存容量有限,必须通过恰当的检索策略和检索方式来限制加载对象的数目。Session的 evit()方法可以显式清空缓存中特定对象,但这种方法不值得推荐。第二级缓存的物理介质可以是内存和硬盘,因此第二级缓存可以存放大量的数据,数据过期策略的maxElementsInMemory属性值可以控制内存中的对象数目。管理第二级缓存主要包括两个方面:选择需要使用第二级缓存的持久类,设置合适的并发访问策略:选择缓存适配器,设置合适的数据过期策略。
二. 一级缓存的管理:
当应用程序调用Session的save()、update()、savaeOrUpdate()、get()或load(),以及调用查询接口的 list()、iterate()或filter()方法时,如果在Session缓存中还不存在相应的对象,Hibernate就会把该对象加入到第一级缓存中。当清理缓存时,Hibernate会根据缓存中对象的状态变化来同步更新数据库。 Session为应用程序提供了两个管理缓存的方法: evict(Object obj):从缓存中清除参数指定的持久化对象。 clear():清空缓存中所有持久化对象。
三. Hibernate二级缓存的管理:
1. Hibernate二级缓存策略的一般过程如下:
1) 条件查询的时候,总是发出一条select * from table_name where …. (选择所有字段)这样的SQL语句查询数据库,一次获得所有的数据对象。
2) 把获得的所有数据对象根据ID放入到第二级缓存中。
3) 当Hibernate根据ID访问数据对象的时候,首先从Session一级缓存中查;查不到,如果配置了二级缓存,那么从二级缓存中查;查不到,再查询数据库,把结果按照ID放入到缓存。
4) 删除、更新、增加数据的时候,同时更新缓存。
Hibernate二级缓存策略,是针对于ID查询的缓存策略,对于条件查询则毫无作用。为此,Hibernate提供了针对条件查询的Query Cache。
2. 什么样的数据适合存放到第二级缓存中?
1) 很少被修改的数据
2) 不是很重要的数据,允许出现偶尔并发的数据
3) 不会被并发访问的数据
4) 参考数据,指的是供应用参考的常量数据,它的实例数目有限,它的实例会被许多其他类的实例引用,实例极少或者从来不会被修改。
3. 不适合存放到第二级缓存的数据?
1) 经常被修改的数据
2) 财务数据,绝对不允许出现并发
3) 与其他应用共享的数据。
4. 常用的缓存插件 Hibernater二级缓存是一个插件,下面是几种常用的缓存插件:
◆EhCache:可作为进程范围的缓存,存放数据的物理介质可以是内存或硬盘,对Hibernate的查询缓存提供了支持。
◆OSCache:可作为进程范围的缓存,存放数据的物理介质可以是内存或硬盘,提供了丰富的缓存数据过期策略,对Hibernate的查询缓存提供了支持。
◆SwarmCache:可作为群集范围内的缓存,但不支持Hibernate的查询缓存。
◆JBossCache:可作为群集范围内的缓存,支持事务型并发访问策略,对Hibernate的查询缓存提供了支持。
5. 配置Hibernate二级缓存的主要步骤:
1) 选择需要使用二级缓存的持久化类,设置它的命名缓存的并发访问策略。这是最值得认真考虑的步骤。
2) 选择合适的缓存插件,然后编辑该插件的配置文件。
关于Hibernate二级缓存的问题
15:02:02,000 WARN EhCacheProvider:86 - Could not find configuration [com.nacosoft.pda.role.PdaRole]; using defaults.
不必管它就行了,呵呵。
意思是找不到你的PdaRole所使用的二级缓存配置文件,将使用默认配置,也就是src/EnCache.xml里面的配置。
当然你也可以手动的为每个类添加配置文件,不过没必要。
http://yuleihome.javaeye.com/blog/173716这里较为详细
1,检查一下缓存供应商有没有问题.
2,
这样
org.hibernate.cache.EhCacheProvider
----------------------->
写成这样
org.hibernate.cache.EhCacheProvider
这里会出未知错误.
com.nacosoft.pda.user.PdaUser 有没有这些类啊 是不是路径写错了啊
could
not
instantiate
RegionFactory
不能实例化
<property
name="hibernate.cache.use_second_level_cache">true
<property
name="hibernate.cache.provider_class">org.hibernate.cache.ehcacheprovider
前一句是打开二级缓存,后一句是启用第三方缓存产品(可改变,上面eache是hibernate官方默认的第三方缓存产品)
缓存是否实用,要看你的需求,
如果你的系统,浏览的人数比较多,但是增删的比较少,缓存的功劳非常大
如果你的系统即时性非常强,那么缓存的命中率就比较低,同时更新数据时,hibernate需要额外提供资源维护缓存与数据的一致
</property
</property
hibernate二级缓存,ehcache.xml文件在哪
找到了使用二级缓存的相关资料。我就不贴过过来了。自己 去看http://developer.51cto.com/art/201202/315922.htm
合理的缓存应用可以极大地提高系统性能,最简单的是在应用层面做缓存(越高层面做缓存,效果往往越好),直接将数据缓存到服务器中,以全局map方式存储。在使用的时候直接从缓存的map中取,而不用连接数据库,从而提升性能。这种方式简单易行,但是map常驻服务器内存,并且在数据变更(增删改)的时候要手动更新map。还有一种方式比较通用,就是使用Hibernate二级缓存(SessionFactory级别的全局缓存,进程或集群级别),是一种通用缓存(一级缓存就不说了,Session级别缓存,hibernate自己管理),hibernate二级缓存多应用在多读少写的实体对象中,比如组织机构和系统字典。本文使用hibernate注解方式使用二级缓存,做一个说明(使用Ehcache)。1、添加ehcache.xml配置文件2、hibernate配置文件中,配置Ehcache相关属性hibernate.cache.use_second_level_cache=truehibernate.cache.use_query_cache=truehibernate.cache.provider_class=org.hibernate.cache.EhCacheProviderhibernate.generate_statistics=true调试的时候,可以设置log4j的log4j.logger.org.hibernate.cache=debug(记录二级缓存的活动),实际发布的时候,注释掉,以免影响性能。3、pom文件中引入相应jar包(Maven项目,如果还在手动添加jar包的,可以尝试使用maven)org.hibernatehibernate-ehcache3.6.9.Final4、注解方式配置实体配置了二级缓存后,并不是对所有的实体使用,而是需要指定哪些实体需要用到。如果不配置查询缓存(查询缓存会在下面讲到),则只会在根据id查询的操作中,缓存对象。在实体上配置@Cache(usage=CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)并指定缓存并发策略。@Entity@Cache(usage=CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)@Table(name="base_dict")@JsonIgnoreProperties(value={"hibernateLazyInitializer","handler","fieldHandler","parentDict"})publicclassDictimplementsSerializable{/****/privatestaticfinallongserialVersionUID=5569761380050L;@Id@Column(name="id",length=36)@GeneratedValue(generator="uuid")@GenericGenerator(name="uuid",strategy="org.hibernate.id.UUIDGenerator")@JsonProperty("id")privateStringid;/**字典名称*/@ForeignShow@Column(name="name",length=200)privateStringname;5、查询缓存的使用Queryquery=session.createQuery(hql);query.setCacheable(true);//启用查询缓存query.setCacheRegion(“queryCacheRegion”);//设置查询缓存区域(数据过期策略)QueryCache只是在特定的条件下才会发挥作用,而且要求相当严格:(1)完全相同的HQL重复执行。(注意,只有hql)(2)重复执行期间,QueryCache对应的数据表不能有数据变动(比如添、删、改操作)绝大多数的查询并不能从查询缓存中受益,所以Hibernate默认是不进行查询缓存的。查询缓存适用于以下场合:(1)在应用程序运行时经常使用的查询语句(参数相同)(2)很少对与查询语句检索到的数据进行插入、删除或更新操作query.list();
hibernate 一级缓存session关闭后失效。二级缓存什么时候失效?
在session关闭前先进行清理缓存区,然后再关闭session对象,释放资源。
当sessionFactory对象关闭的情况下二级缓存也就关闭了。
二级缓存是factory级别的,二级缓存被清除的时候会失效,例如:执行了executeUpdate等语句。