Ehcache与数据库不同步

时间:2012-04-24 19:40:42

标签: java java-ee concurrency ehcache race-condition

在使用CMT的Java EE服务器上,我使用ehcache在业务对象层(EJB)和数据访问层(使用JDBC的POJO)之间实现缓存层。我似乎遇到了两个线程在使用自填充Ehcache时访问同一记录的竞争条件。缓存是在记录的主键上键入的。

场景是:

  1. 第一个线程更新数据库中的记录并从缓存中删除记录(但数据库提交不一定立即发生 - 可能还有其他查询要遵循。)
  2. 第二个线程读取记录,导致重新填充缓存。
  3. 第一个线程提交事务。
  4. 这一切都在不到一秒钟内发生。这会导致缓存与数据库不同步,并且后续读取记录会返回过时的缓存数据,直到执行另一次更新,或者该条目从缓存中过期。我可以处理短期的陈旧数据(典型的交易长度),但不能分钟,这是我想要缓存对象的时间。

    有关避免这种竞争条件的建议吗?

    更新

    在事务提交后清除缓存肯定是理想的。问题是,在使用CMT的J2EE环境中,当缓存层夹在业务层(无状态会话EJB)和数据访问层之间时,如何做到这一点?

    为了清楚这种强加的约束,所讨论的方法调用可能与在之前或之后发生的其他方法调用处于同一事务中,也可能不在同一事务中。我无法强制提交(或在单独的事务中执行此操作),因为这会改变事务边界与客户端代码所期望的。任何后续异常都不会回滚整个事务(在这种情况下,不必要地清除缓存是可接受的副作用)。我无法控制事务的入口点,因为它本质上是客户端可以使用的API。将清除缓存的可靠性推向客户端应用程序是不合理的。

    我希望能够推迟任何缓存清除操作,直到EJB容器提交整个事务,但我发现没有办法挂钩该逻辑并使用无状态会话bean运行我自己的代码。

    更新#2:

    迄今为止最有希望的解决方案是使用ehcache 2.0的JTA支持:http://ehcache.org/documentation/apis/jta

    这意味着升级到ehcache 2.x并为数据库启用XA事务,这可能会产生负面的副作用。但它似乎是“正确”的方式。

1 个答案:

答案 0 :(得分:0)

您正在使用交易 - 在commit 之后删除缓存更有意义,即更改真的发生时。

通过这种方式,您只能在事务处理期间看到旧数据,之后的所有读取都会显示最新视图。

更新:由于这是特定于CMT的,因此您应该查看SessionSynchronization界面及其afterCompletion()方法。这显示在this tutorial.