hibernate二级缓存中关联的脏读

时间:2014-12-26 15:50:03

标签: spring hibernate transactions ehcache

当启用ehCache(2.7.0)作为Hibernate(4.3.7)二级缓存时,Hibernate会返回旧的集合关联。

型号:会员拥有一个包含电子钱包交易的电子钱包。

场景:将Wallet交易添加到交易中的成员(启用了ehcache)。但是,在场景之后(提交之后),会员中的钱包交易不存在,而它在数据库中存在。

测试代码的方案:

startTransaction(); // used to create a transaction through Spring.
member = findMemberById(); // Hibernate "get()" to retrieve member from Db.
final WalletTransaction walTx = member.getEnsureWallet().addWalletTransaction(10); // add wallet tx of 10 euro.
member.saveOrUpdate(); // will update the member and the wallet transactions through cascading
commitTransaction();

// assert wallet transaction is present
startTransaction();
final Taxer mem = findMemberById(member.getId()); // refresh member in session through it's PK, logging indicates it comes from cache.
// final Taxer mem = findMemberByLoginName(member.getLoginName()); // when retrieving the member through it's loginName, the test works.
assertTrue(mem.containsWalletTransaction(walTx)); // FAILS
commitTransaction();

hibernate模型成员代码段

<class name="com.core.domain.MemberDefault" table="mem" discriminator-value="Mem" >
   <component name="wallet" class="com.core.domain.Wallet">
        <set name="transactions" table="wallet_tx" cascade="save-update, delete" >
            <!--cache usage="read-write" /-->
            <key column="idMember" not-null="true" />

            <composite-element class="com.core.domain.WalletTransactionDefault">
              <property name="amount" type="big_decimal" column="amount" />
               .... (more props)
            </composite-element>
        </set>
  </component>
</class

MemberDefault和WalletDefault类摘要:

public class MemberDefault implements Member {
  private Wallet wallet;
....
}

public class WalletDefault implements Wallet {
 private Set<WalletTransaction> transactions;

public void setTransactions(Set<WalletTransaction> transactions) {
  this.transactions = transaction;
 }

 public Set<WalletTransaction> getTransactions() {
  return this.transactions;
 }
}

注意:

  1. 如果我没有在事务中添加钱包事务(删除第一个启动/提交),则测试成功执行(以上是隔离测试代码以重现错误)。
  2. 如果我关闭第二级,则测试有效。
  3. 如果我没有通过它的PK从Db中检索成员,而是通过它的loginName,以便Hibernate使用查询,并且如此查询缓存,测试工作。
  4. 我调试了,启用了hibernate / ehcache调试日志,修改了hibernate中的缓存设置,尝试了较旧的Hibernate 4和ehCache版本,但似乎没有解决它,有点令人沮丧。

    请就如何解决这个问题提出一些建议?

1 个答案:

答案 0 :(得分:0)

我通过总是将一个实例分配给MemberDefault中的wallet字段(hibernate组件)来解决它。 也就是说,而不是:

private Wallet wallet;

我们必须使用:

private Wallet wallet = new WalletDefault();
在MemberDefault类中

这是一个错误,还是有任何逻辑? 我认为这是一个错误,因为Hibernate知道它是来自hibernate配置的WalletDefault类型的组件。 (我通过删除Wallet组件进行测试来发现它)