Hibernate/Ehcache:从二级缓存中清除集合与其他数据库读取不同步

9
我有一个使用JPA、Hibernate和ehcache的应用程序,以及Spring的声明式事务。数据库的负载相当高,所以为了加速操作,包括集合在内的所有内容都被缓存。现在并不是秘密,集合与拥有它们的实体分别被缓存,因此,如果我删除一个作为这种缓存集合中元素的实体,保存应该成为其中一个元素的实体,或者更新实体使其从一个集合移动到另一个集合,我就必须手动执行逐出。
因此,我使用一个Hibernate事件监听器来跟踪正在插入、删除或更新的实体,并将该信息保存到注册到Spring事务管理器的事务同步中。一旦提交事务,同步就会执行逐出。
现在的问题是,很多时候,一些其他并发事务设法找到了刚刚被逐出的缓存集合(根据日志,这些事件通常相隔数秒),自然会导致EntityNotFoundException的发生。
如何正确同步这些东西?
我尝试在TransactionSynchronization的4个方法中的每个方法中执行逐出(它们相对于事务完成时间的不同点调用),但没有帮助。
3个回答

3
基本上,您需要在集合正在或已被驱逐的过程中强制从数据库中读取数据。一种方法是在收到清除请求但在进入更改事务之前将集合标记为脏。任何并发事务都会检查脏标志,如果其设置为true,则应从数据库中获取数据,否则可以从缓存中读取。您可能需要更改DB事务设置,以便并发事务阻塞,直到更新数据的事务完成,以便从DB读取正确的数据。事务完成后,您可以将脏标志重置为false。
当更新、插入或删除即将到来且驱逐持续存在时,您还可以在缓存的集合上创建锁定。这将确保在驱逐过程结束之前,没有其他事务可以读取/更改缓存的集合。

顺便提一下,它是在事务之外被驱逐的。我得找一下API来标记它们为脏数据,谢谢。另外,我该如何让Hibernate在你建议添加的锁上同步? - Kirill
1
显然,PersistentCollection的脏标记不起作用,因为不同的事务会得到相同集合的不同实例。 至于锁定,我接下来会研究一下,并且非常感谢如果有人能指向正确的API。 据我所知,EhCache不支持锁定,首先看了它。 - Kirill

0

0
为什么你不能保持集合的最新状态?例如,当你添加一个对象时,将该对象添加到它所属的集合中。当你删除一个对象时,从它所在的集合中移除它。根据我的经验,在使用 Hibernate 或 JPA 缓存时,对象的状态(而不是数据库的状态)被缓存,因此你需要确保内存中的对象模型与数据库中的对象模型同步。
或者我有什么遗漏吗?为什么你不能简单地保持集合的最新状态?

1
这是一个多线程应用程序,传递相同的最新实例和最新集合似乎有点困难,因为存在各种并发操作,这些操作需要不同的时间来完成,而我倾向于经常使用EntityManager.getById来获取实体的最新状态。 - Kirill

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接