事务二级缓存和生成标识符

时间:2012-06-07 15:35:24

标签: spring hibernate jta infinispan atomikos

我有以下堆栈:

  • Hibernate 3.6.9.Final
  • Spring 3.1.1
  • Atomikos 3.7.1
  • Infinispan 4.2.1.FINAL
  • MySQL的

我一直在编写一些测试来确保在抛出RuntimeException时,当前事务在数据库上回滚,但也在事务2LC上回滚。

我发现发现了一些奇怪的结果,我希望有人可以解释。

如果我使用@Cache注释@Entity(usage = CacheConcurrencyStrategy.TRANSACTIONAL)和String @Id,我会在分配id并保存实体时看到我期望的结果:

  • 当没有抛出异常时,事务被提交而2LC包含实体,我使用以下方式确认:

sessionFactory.getCache().containsEntity(MyEntity.class, myIdentifier)

  • 如果抛出异常,则数据库或2LC都不包含该实体。

但是,如果我使用生成@Entity(MySQL自动递增long属性)的@Id重复这些测试,如下所示:

@Id
@GeneratedValue
private long id;

我发现实体永远不会被放入2LC中,无论抛出任何异常。

我已经完成了一些调试,它似乎归结为AbstractSaveEventListener#performSaveOrReplicate中的不同代码路径。对于已分配的@Id,useIdentityColumn为false,因此我们实例化并执行EntityInsertAction,然后将新实体放入2LC中。

相反,如果@Id由MySQL生成,我们发现useIdentityColumn为true,我们实例化并执行EntityIdentityInsertAction。这包含有关2LC的注释掉的代码,如下所示:

      //TODO: this bit actually has to be called after all cascades!
      //but since identity insert is called *synchronously*,
      //      instead of asynchronously as other actions, it isn't
      /*if ( persister.hasCache() && !persister.isCacheInvalidationRequired() ) {
         cacheEntry = new CacheEntry(object, persister, session);
         persister.getCache().insert(generatedId, cacheEntry);
      }*/

这有什么理由吗?缓存插入是否应该在其他地方完成?这是一个错误吗?

如果有人能够阐明这种差异,以及这应该如何运作,我将非常感激。

我在Hibernate论坛上发布了这个question,但没有太多兴趣。

1 个答案:

答案 0 :(得分:1)

我还认为这对二级缓存的使用是一个非常大的限制所以我创建了一个issue(HHH-7964)。我还添加了一个解决方法,但这只是一个概念证明,据我所知,不应该用于生产。