我是 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 继续做家务活动,最后将查询结果添加到查询缓存中(注意时间戳将高于线程 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 隔离级别设置为可重复读取(但是不要认为这会有所帮助,因为在从数据库读取数据后会添加到缓存逻辑)b)手动强制标准查询缓存驱逐实体删除/更新 c)做根本不使用查询缓存(尝试路由大多数数据库查询以使用第二个缓存)
以前有人遇到过这个问题吗?