9

我正在使用 java 1.6、spring 2.5、hibernate 3.3.1 和 ehcache 2.6.0。程序连接到两个数据库。有两种 ehcache 配置,但在这种情况下只使用一种。在批处理结束时,程序返回此错误:

    2012-10-23 15:44:43,406 ERROR (AbstractReadWriteEhcacheAccessStrategy.java:159) - Cache dao.data.MyObject Key dao.data.MyObject#28 Lockable : null
A soft-locked cache entry was removed already. Out of balance lock/unlock sequences ?

什么会产生这个错误?

4

2 回答 2

6

我现在被这个打击了,所以我会分享我的发现。

首先,一些背景:

  • 我们使用 Hibernate 3.5.2 & EhCache 2.7.0
  • 只有一个数据库(另一个以只读方式访问,但没有使用缓存,因为它是在外部更新的)和单个缓存实例(无集群)
  • 问题发生在更新与 InheritanceType.JOINED 和 CacheConcurrencyStrategy.READ_WRITE 映射的实体时(但不是当我们切换到 NONSTRICT_READ_WRITE 时)。另外,从代码检查来看,删除时也会发生这种情况。

我通过调试 Hibernate 和 EhCache 代码发现了什么:

  1. Hibernate 的 EntityUpdateAction(在 execute() 中)调用 EntityRegionAccessStrategy.lockItem()
  2. EhCache 的实现(在 AbstractReadWriteEhcacheAccessStrategy 中)将给定键的映射从缓存实体更改为锁
  3. Hibernate 检测到实体映射到超过 1 个表,因此需要缓存失效(参见 AbstractEntityPersister.isCacheInvalidationRequired())
  4. 它继续调用 persister.getCacheAccessStrategy().remove(),在 EhCache 的实现中,它删除给定缓存键的映射。然而,虽然 Hibernate 预计这实际上会删除缓存的实体,但使用 EhCache 它会删除锁(在步骤 2 中放置了锁)。
  5. 事务完成后,在 EntityUpdateAction.doAfterTransactionCompletion() 中,Hibernate 检测到需要缓存失效,并继续调用 unlockItem(),如果没有给定缓存键的映射,则会失败,从而导致您描述的错误消息

在我看来,这是 lockItem() 和 unlockItem() 的 EhCache 实现中的一个问题(在 READ_WRITE 情况下)。它不应该用锁代替实际物品,而是单独存储锁。至少,可以说 Hibernate 和 EhCache 在这种情况下不是 100% 兼容的。

最后几点说明:

  • 这个错误似乎是无害的,可以通过 log4j 配置安全地抑制。
  • 我设法在不同的场景中重复了这一点(归结为相同的锁定/删除/解锁序列)。这一次,不是加入继承,而是原生 SQL 触发了删除。其他一切都差不多。
  • Hibernate 和 EhCache 代码的相关位:EntityRegionAccessStrategy、EntityAction、CollectionRegionAccessStrategy、CollectionAction 和相关的实现/扩展具体类。

高温高压

于 2013-04-18T14:41:48.427 回答
2

我在使用 createSQLQuery(Native SQL Query) 时遇到了同样的问题。由于本机 sql 查询对 hibernate 的二级缓存的影响,我解决了我的问题。

来自链接:主要原因是原生查询会使二级缓存失效。链接底部还有解决方案,防止hibernate在使用原生sql查询时使二级缓存失效。

于 2013-10-31T04:15:01.320 回答