1、关于hibernate缓存的问题
Hibernate缓存分为二级,第一级存放于session中称为一级缓存。第二级是由sessionFactory控制的进程级缓存。是全局共享的缓存。查询时使用缓存的实现过程为:首先查询一级缓存中是否具有需要的数据,如果没有,查询二级缓存,如果二级缓存中也没有,此时再执行查询数据库的工作。
hibernate会自行维护二级缓存中的数据,以保证缓存中的数据和数据库中的真实数据的一致性!也就是说删除、更新、增加数据的时候,同时更新缓存,也包括二级缓存!
当执行load()、 get()、list()、iterate() 或scroll()方法获得一个对象时, 该对象都将被加入到Session的内部缓存中。
2、适合于使用二级缓存的情况
1、数据不会被第三方修改;
一般情况下,会被hibernate以外修改的数据最好不要配置二级缓存,以免引起不一致的数据。但是如果此数据因为性能的原因需要被缓存,同时又有可能被第3方比如SQL修改,也可以为其配置二级缓存。只是此时需要在sql执行修改后手动调用cache的清除方法。以保证数据的一致性
数据大小在可接收范围之内;
如果数据表数据量特别巨大,此时不适合于二级缓存。原因是缓存的数据量过大可能会引起内存资源紧张,反而降低性能。
如果数据表数据量特别巨大,但是经常使用的往往只是较新的那部分数据。此时,也可为其配置二级缓存。但是必须单独配置其持久化类的缓存策略,比如最大缓存数、缓存过期时间等,将这些参数降低至一个合理的范围(太高会引起内存资源紧张,太低了缓存的意义不大)。
数据更新频率低;
对于数据更新频率过高的数据,频繁同步缓存中数据的代价可能和 查询缓存中的数据从中获得的好处相当,坏处益处相抵消。此时缓存的意义也不大。
非关键数据(不是财务数据等)
财务数据等是非常重要的数据,绝对不允许出现或使用无效的数据,所以此时为了安全起见最好不要使用二级缓存。因为此时 “正确性”的重要性远远大于 “高性能”的重要性。
3、Hibernate几个方法的比较
List方法:
List方法从不使用二级缓存,但会向二级缓存中持久化查询结果。也就是List方法每次都会从数据进行查询,并且如果启用了二级缓存,则Hibernate同时会将所有查询结果初始化为持久化对象,如果结果集较大时,这将会占用很多的处理时间。
Iterate方法:
在无二级缓存的情况下:iterate()方法具有著名的 “n+1” 次查询的问题,也就是说在第一次查询时iterate方法会执行满足条件的查询结果数再加一次(n+1)的查询。如果启用了二级缓存,iterate()方法的查询过程将是:首先查询一级缓存中是否具有需要的数据,如果没有,查询二级缓存,如果二级缓存中也没有,此时再执行查询数据库的工作。
以下是测试的几组数据:
机器环境:P43.06 512MB WINXP SP2 MySql5.0.22
数据库记录=取出记录数 |
无缓存 |
缓存 | |||
List |
Iterate |
List |
iterate | ||
1000 |
1 |
704 |
1156 |
3406 |
391 |
2 |
203 |
750 |
203 |
204 | |
3 |
47 |
782 |
93 |
187 | |
4 |
47 |
578 |
79 |
46 | |
5 |
125 |
562 |
125 |
63 | |
2000 |
1 |
1265 |
2719 |
9438 |
531 |
2 |
203 |
1750 |
250 |
266 | |
3 |
188 |
1718 |
250 |
157 | |
4 |
125 |
1719 |
265 |
235 | |
5 |
187 |
1766 |
235 |
265 | |
4000 |
1 |
1438 |
4328 |
16422 |
875 |
2 |
344 |
3344 |
485 |
453 | |
3 |
312 |
3235 |
328 |
453 | |
4 |
312 |
3172 |
484 |
500 | |
5 |
313 |
3203 |
375 |
438 |
100000记录集情况下
无缓存情况取单条数据10次list平均:6 ms
无缓存情况取单条数据10次iterate平均:13 ms
有缓存情况取单条数据10次iterate平均:10 ms
100000记录集情况下
无缓存情况取20条数据10次list平均:20 ms
无缓存情况取20条数据10次iterate平均:78 ms
有缓存情况取20条数据10次iterate平均:20ms
100000记录集情况下
无缓存情况取60条数据10次list平均:20 ms
无缓存情况取60条数据10次iterate平均:170 ms
有缓存情况取60条数据10次iterate平均:26 ms
4、查询策略比较:
在不使用二级缓存的情况下慎用或者不用Iterate()方法,因为它会造成n+1次查询。
在使用二级缓存的情况下,小的数据量并且很小更新的数据可以考虑使用缓存,并且在启动时加载到缓存中。这样在查询时可以使用Iterate()方法来使用二级缓存。
但是注意:当数据量特别大时(比如流水线数据等)需要针对此持久化对象配置其具体的缓存策略,比如设置其存在于缓存中的最大记录数、缓存存在的时间等参数,以避免系统将大量的数据同时装载入内存中引起内存资源的迅速耗尽,反而降低系统的性能!但如果最大记录数、缓存存在的时间,这将会导致缓存命中率很低,这将值得考虑。
5、load()与get()的区别
如果没有匹配的数据库记录,load()方法可能抛出无法恢复的异常(unrecoverable exception)。如果你不确定是否有匹配的行存在,应该使用get()方法,它会立刻访问数据库,如果没有对应的行,会返回null。