[list]
1.1.1. 基本的缓存原理
Hibernate缓存分为二级,第一级存放于session中称为一级缓存,默认带有且不能卸载。
第二级是由sessionFactory控制的进程级缓存。是全局共享的缓存,凡是会调用二级缓存的查询方法 都
会从中受益。只有经正确的配置后二级缓存才会发挥作用。同时在进行条件查询时必须使用相应的方法
才能从缓存中获取数据。比如Query.iterate()方法、load、get方法等。必须注意的是session.find方
法永远是从数据库中获取数据,不会从二级缓存中获取数据,即便其中有其所需要的数据也是如此。
查询时使用缓存的实现过程为:首先查询一级缓存中是否具有需要的数据,如果没有,查询二级缓存,
如果二级缓存中也没有,此时再执行查询数据库的工作。要注意的是:此3种方式的查询速度是依次降低
的。
1.2. 存在的问题
1.2.1. 一级缓存的问题以及使用二级缓存的原因
因为Session的生命期往往很短,存在于Session内部的第一级最快缓存的生命期当然也很短,所以
第一级缓存的命中率是很低的。其对系统性能的改善也是很有限的。当然,这个Session内部缓存的主要
作用是保持Session内部数据状态同步。并非是hibernate为了大幅提高系统性能所提供的。
为了提高使用hibernate的性能,除了常规的一些需要注意的方法比如:
使用延迟加载、迫切外连接、查询过滤等以外,还需要配置hibernate的二级缓存。其对系统整体性能的
改善往往具有立竿见影的效果!
(经过自己以前作项目的经验,一般会有3~4倍的性能提高)
1.2.2. N+1次查询的问题
执行条件查询时,iterate()方法具有著名的 “n+1”次查询的问题,也就是说在第一次查询时
iterate方法会执行满足条件的查询结果数再加一次(n+1)的查询。但是此问题只存在于第一次查询时
,在后面执行相同查询时性能会得到极大的改善。此方法适合于查询数据量较大的业务数据。
但是注意:当数据量特别大时(比如流水线数据等)需要针对此持久化对象配置其具体的缓存策略,比
如设置其存在于缓存中的最大记录数、缓存存在的时间等参数,以避免系统将大量的数据同时装载入内
存中引起内存资源的迅速耗尽,反而降低系统的性能!!!
1.3. 使用hibernate二级缓存的其他注意事项:
1.3.1. 关于数据的有效性
另外,hibernate会自行维护二级缓存中的数据,以保证缓存中的数据和数据库中的真实数据的一致性!
无论何时,当你调用save()、update()或 saveOrUpdate()方法传递一个对象时,或使用load()、 get()
、list()、iterate() 或scroll()方法获得一个对象时, 该对象都将被加入到Session的内部缓存中。
当随后flush()方法被调用时,对象的状态会和数据库取得同步。
也就是说删除、更新、增加数据的时候,同时更新缓存。当然这也包括二级缓存!
只要是调用hibernate API执行数据库相关的工作。hibernate都会为你自动保证 缓存数据的有效性!!
但是,如果你使用了JDBC绕过hibernate直接执行对数据库的操作。此时,Hibernate不会/也不可能自行
感知到数据库被进行的变化改动,也就不能再保证缓存中数据的有效性!!
这也是所有的ORM产品共同具有的问题。幸运的是,Hibernate为我们暴露了Cache的清除方法,这给我们
提供了一个手动保证数据有效性的机会!!
一级缓存,二级缓存都有相应的清除方法。
其中二级缓存提供的清除方法为:
按对象class清空缓存
按对象class和对象的主键id清空缓存
清空对象的集合中的缓存数据等。
1.3.2. 适合使用的情况
并非所有的情况都适合于使用二级缓存,需要根据具体情况来决定。同时可以针对某一个持久化对象配
置其具体的缓存策略。
适合于使用二级缓存的情况:
1、数据不会被第三方修改;
一般情况下,会被hibernate以外修改的数据最好不要配置二级缓存,以免引起不一致的数据。但是如果
此数据因为性能的原因需要被缓存,同时又有可能被第3方比如SQL修改,也可以为其配置二级缓存。只
是此时需要在sql执行修改后手动调用cache的清除方法。以保证数据的一致性
2、数据大小在可接收范围之内;
如果数据表数据量特别巨大,此时不适合于二级缓存。原因是缓存的数据量过大可能会引起内存资
源紧张,反而降低性能。
如果数据表数据量特别巨大,但是经常使用的往往只是较新的那部分数据。此时,也可为其配置二级缓
存。但是必须单独配置其持久化类的缓存策略,比如最大缓存数、缓存过期时间等,将这些参数降低至
一个合理的范围(太高会引起内存资源紧张,太低了缓存的意义不大)。
3、数据更新频率低;
对于数据更新频率过高的数据,频繁同步缓存中数据的代价可能和 查询缓存中的数据从中获得的
好处相当,坏处益处相抵消。此时缓存的意义也不大。
4、非关键数据(不是财务数据等)
财务数据等是非常重要的数据,绝对不允许出现或使用无效的数据,所以此时为了安全起见最好不要
使用二级缓存。
因为此时 “正确性”的重要性远远大于 “高性能”的重要性。
2. 目前系统中使用hibernate缓存的建议
1.4. 目前情况
一般系统中有三种情况会绕开hibernate执行数据库操作:
1、多个应用系统同时访问一个数据库
此种情况使用hibernate二级缓存会不可避免的造成数据不一致的问题,
此时要进行详细的设计。比如在设计上避免对同一数据表的同时的写入操作,
使用数据库各种级别的锁定机制等。
2、动态表相关
所谓“动态表”是指在系统运行时根据用户的操作系统自动建立的数据表。
比如“自定义表单”等属于用户自定义扩展开发性质的功能模块,因为此时数据表是运行时建立的,
所以不能进行hibernate的映射。因此对它的操作只能是绕开hibernate的直接数据库JDBC操作。
如果此时动态表中的数据没有设计缓存,就不存在数据不一致的问题。
[/list]
1.1.1. 基本的缓存原理
Hibernate缓存分为二级,第一级存放于session中称为一级缓存,默认带有且不能卸载。
第二级是由sessionFactory控制的进程级缓存。是全局共享的缓存,凡是会调用二级缓存的查询方法 都
会从中受益。只有经正确的配置后二级缓存才会发挥作用。同时在进行条件查询时必须使用相应的方法
才能从缓存中获取数据。比如Query.iterate()方法、load、get方法等。必须注意的是session.find方
法永远是从数据库中获取数据,不会从二级缓存中获取数据,即便其中有其所需要的数据也是如此。
查询时使用缓存的实现过程为:首先查询一级缓存中是否具有需要的数据,如果没有,查询二级缓存,
如果二级缓存中也没有,此时再执行查询数据库的工作。要注意的是:此3种方式的查询速度是依次降低
的。
1.2. 存在的问题
1.2.1. 一级缓存的问题以及使用二级缓存的原因
因为Session的生命期往往很短,存在于Session内部的第一级最快缓存的生命期当然也很短,所以
第一级缓存的命中率是很低的。其对系统性能的改善也是很有限的。当然,这个Session内部缓存的主要
作用是保持Session内部数据状态同步。并非是hibernate为了大幅提高系统性能所提供的。
为了提高使用hibernate的性能,除了常规的一些需要注意的方法比如:
使用延迟加载、迫切外连接、查询过滤等以外,还需要配置hibernate的二级缓存。其对系统整体性能的
改善往往具有立竿见影的效果!
(经过自己以前作项目的经验,一般会有3~4倍的性能提高)
1.2.2. N+1次查询的问题
执行条件查询时,iterate()方法具有著名的 “n+1”次查询的问题,也就是说在第一次查询时
iterate方法会执行满足条件的查询结果数再加一次(n+1)的查询。但是此问题只存在于第一次查询时
,在后面执行相同查询时性能会得到极大的改善。此方法适合于查询数据量较大的业务数据。
但是注意:当数据量特别大时(比如流水线数据等)需要针对此持久化对象配置其具体的缓存策略,比
如设置其存在于缓存中的最大记录数、缓存存在的时间等参数,以避免系统将大量的数据同时装载入内
存中引起内存资源的迅速耗尽,反而降低系统的性能!!!
1.3. 使用hibernate二级缓存的其他注意事项:
1.3.1. 关于数据的有效性
另外,hibernate会自行维护二级缓存中的数据,以保证缓存中的数据和数据库中的真实数据的一致性!
无论何时,当你调用save()、update()或 saveOrUpdate()方法传递一个对象时,或使用load()、 get()
、list()、iterate() 或scroll()方法获得一个对象时, 该对象都将被加入到Session的内部缓存中。
当随后flush()方法被调用时,对象的状态会和数据库取得同步。
也就是说删除、更新、增加数据的时候,同时更新缓存。当然这也包括二级缓存!
只要是调用hibernate API执行数据库相关的工作。hibernate都会为你自动保证 缓存数据的有效性!!
但是,如果你使用了JDBC绕过hibernate直接执行对数据库的操作。此时,Hibernate不会/也不可能自行
感知到数据库被进行的变化改动,也就不能再保证缓存中数据的有效性!!
这也是所有的ORM产品共同具有的问题。幸运的是,Hibernate为我们暴露了Cache的清除方法,这给我们
提供了一个手动保证数据有效性的机会!!
一级缓存,二级缓存都有相应的清除方法。
其中二级缓存提供的清除方法为:
按对象class清空缓存
按对象class和对象的主键id清空缓存
清空对象的集合中的缓存数据等。
1.3.2. 适合使用的情况
并非所有的情况都适合于使用二级缓存,需要根据具体情况来决定。同时可以针对某一个持久化对象配
置其具体的缓存策略。
适合于使用二级缓存的情况:
1、数据不会被第三方修改;
一般情况下,会被hibernate以外修改的数据最好不要配置二级缓存,以免引起不一致的数据。但是如果
此数据因为性能的原因需要被缓存,同时又有可能被第3方比如SQL修改,也可以为其配置二级缓存。只
是此时需要在sql执行修改后手动调用cache的清除方法。以保证数据的一致性
2、数据大小在可接收范围之内;
如果数据表数据量特别巨大,此时不适合于二级缓存。原因是缓存的数据量过大可能会引起内存资
源紧张,反而降低性能。
如果数据表数据量特别巨大,但是经常使用的往往只是较新的那部分数据。此时,也可为其配置二级缓
存。但是必须单独配置其持久化类的缓存策略,比如最大缓存数、缓存过期时间等,将这些参数降低至
一个合理的范围(太高会引起内存资源紧张,太低了缓存的意义不大)。
3、数据更新频率低;
对于数据更新频率过高的数据,频繁同步缓存中数据的代价可能和 查询缓存中的数据从中获得的
好处相当,坏处益处相抵消。此时缓存的意义也不大。
4、非关键数据(不是财务数据等)
财务数据等是非常重要的数据,绝对不允许出现或使用无效的数据,所以此时为了安全起见最好不要
使用二级缓存。
因为此时 “正确性”的重要性远远大于 “高性能”的重要性。
2. 目前系统中使用hibernate缓存的建议
1.4. 目前情况
一般系统中有三种情况会绕开hibernate执行数据库操作:
1、多个应用系统同时访问一个数据库
此种情况使用hibernate二级缓存会不可避免的造成数据不一致的问题,
此时要进行详细的设计。比如在设计上避免对同一数据表的同时的写入操作,
使用数据库各种级别的锁定机制等。
2、动态表相关
所谓“动态表”是指在系统运行时根据用户的操作系统自动建立的数据表。
比如“自定义表单”等属于用户自定义扩展开发性质的功能模块,因为此时数据表是运行时建立的,
所以不能进行hibernate的映射。因此对它的操作只能是绕开hibernate的直接数据库JDBC操作。
如果此时动态表中的数据没有设计缓存,就不存在数据不一致的问题。
[/list]