我是java / spring / hibernate的新手,经过几年的.Net编程后,我真的很喜欢java。
现在我正在使用Spring(MVC,声明式事务)和Hibernate(3.6,作为缓存提供者--ehCache 2.5)开发Web应用程序。我有一些只读和读写的设置,我想使用Hibernate第二个缓存和查询缓存进行缓存。
当我将缓存用于只读实体时,一切都很好。我添加了读写实体并使用jMeter运行了性能测试。对于读写实体,我面临着不可重复读取的问题。例如。有几个并发线程读写实体表。线程3获取查找值:
16:34:45,304 DEBUG [http-bio-8080-exec-3] cache.StandardQueryCache: (StandardQueryCache.java:136) - cached query results were not up to date
16:34:45,304 DEBUG [http-bio-8080-exec-3] hibernate.SQL:(SQLStatementLogger.java:111) - select virtualdev0_.virtual_device_class_id as virtual1_45_, virtualdev0_.virtual_device_class as virtual2_45_, virtualdev0_.sitebox_id as sitebox3_45_, virtualdev0_.timestamp as timestamp45_ from virtual_device_class virtualdev0_ where virtualdev0_.sitebox_id=?
它发现缓存不是最新的并且加载实体,将它们添加到二级缓存,实现并返回......从这里到16:34:45,826的连续过程
同时,线程9删除一个实体并更新二级缓存+时间戳:
16:34:45,799 DEBUG [http-bio-8080-exec-9] hibernate.SQL:(SQLStatementLogger.java:111) - delete from virtual_device_class where virtual_device_class_id=?
16:34:45,814 DEBUG [http-bio-8080-exec-9] cache.UpdateTimestampsCache:(UpdateTimestampsCache.java:95) - Invalidating space [virtual_device_class], timestamp: 5466792287494145
线程3继续保持活动,最后将查询结果添加到查询缓存中(注意,时间戳将高于timpestamp用于线程9的删除操作):
16:34:45,826 DEBUG [http-bio-8080-exec-3] cache.StandardQueryCache:(StandardQueryCache.java:96) - caching query results in region: org.hibernate.cache.StandardQueryCache; timestamp=5466792287543296
因此,此时删除的ID将在查询缓存中,查询缓存将被视为最新。
16:34:45,852 DEBUG [http-bio-8080-exec-9] cache.UpdateTimestampsCache:(UpdateTimestampsCache.java:122) - [virtual_device_class] last update timestamp: 5466792287494145, result set timestamp: 5466792287543296
因此,当您尝试再次进行查找时,它将查找查询缓存,然后将开始从第二个缓存中实现实体。
16:34:45,852 DEBUG [http-bio-8080-exec-9] cache.StandardQueryCache:(StandardQueryCache.java:140) - returning cached query results
但是已删除的项目不会出现,因此将对db进行查询。
16:34:45,863 DEBUG [http-bio-8080-exec-9] loader.Loader:(Loader.java:2022) - loading entity: [com.test.models.VirtualDeviceClass#0b2f363f-fbb9-4d17-8f86-af86ebb5100c]
16:34:45,873 DEBUG [http-bio-8080-exec-9] hibernate.SQL:(SQLStatementLogger.java:111) - select virtualdev0_.virtual_device_class_id as virtual1_45_0_, virtualdev0_.virtual_device_class as virtual2_45_0_, virtualdev0_.sitebox_id as sitebox3_45_0_, virtualdev0
当我使用Load方法时,如果在db中找不到实体,则抛出异常。 在我的情况下,实体很少会更新它可能会发生,这让我很担心。我几乎没有想法如何克服这个问题:
a)将trx隔离级别设置为可重复读取DB(但不要认为它会有所帮助,因为在从db读取数据后添加到缓存逻辑) b)手动强制标准查询缓存逐出实体删除/更新 c)根本不使用查询缓存(尝试将大多数数据库查询路由到使用第二个缓存)
之前有人面对这个问题吗?
答案 0 :(得分:1)
我已迁移到Hibernate 4,现在工作正常。
此问题可能与方法SessionFactory.getQueryCache(String regionName)