【问题标题】:Spring @Transactional DAO calls return same objectSpring @Transactional DAO 调用返回相同的对象
【发布时间】:2015-09-30 20:03:21
【问题描述】:

我们正在使用 Spring 和 IBatis,我发现了一些有趣的事情,即使用 @Transactional 的服务方法处理返回相同记录的多个 DAO 调用的方式。这是一个不起作用的方法示例。

@Transactional
public void processIndividualTrans(IndvTrans trans) {
Individual individual = individualDAO.selectByPrimaryKey(trans.getPartyId());       

individual.setFirstName(trans.getFirstName());
individual.setMiddleName(trans.getMiddleName());
individual.setLastName(trans.getLastName());

Individual oldIndvRecord = individualDAO.selectByPrimaryKey(trans.getPartyId());
individualHistoryDAO.insert(oldIndvRecord);

individualDAO.updateByPrimaryKey(individual);
}

上述方法的问题是该行的第二次执行 individualDAO.selectByPrimaryKey(trans.getPartyId()) 返回第一次调用返回的精确对象

这意味着 oldIndvRecord 和 individual 是同一个对象,并且行 individualHistoryDAO.insert(oldIndvRecord); 向历史表中添加一行,其中包含更改(我们不想要)。

为了让它工作,它必须看起来像这样。

@Transactional
public void processIndividualTrans(IndvTrans trans) {
Individual individual = individualDAO.selectByPrimaryKey(trans.getPartyId());       
individualHistoryDAO.insert(individual);

individual.setFirstName(trans.getFirstName());
individual.setMiddleName(trans.getMiddleName());
individual.setLastName(trans.getLastName());
individualDAO.updateByPrimaryKey(individual);
}

我们想编写一个名为 updateIndividual 的服务,我们可以将它用于此表的所有更新,它会在执行更新之前在 IndividualHistory 表中存储一行。

@Transactional
public void updateIndividual(Individual individual) {
Individual oldIndvRecord = individualDAO.selectByPrimaryKey(trans.getPartyId());
individualHistoryDAO.insert(oldIndvRecord);
individualDAO.updateByPrimaryKey(individual);
}

但它不会像对象更改之前那样存储行。我们甚至可以在 DAO 调用之前显式地实例化不同的对象,第二个对象变成与第一个对象相同的对象。

我查看了 Spring 文档,但无法确定发生这种情况的原因。

谁能解释一下?

是否有允许第二次 DAO 调用返回数据库内容而不是之前返回的对象的设置?

【问题讨论】:

  • 能贴一下individualDAO和individualHistoryDAO的代码吗?
  • 正确的行为,应该是这样。

标签: java spring duplicates mybatis transactional


【解决方案1】:

您将 Hibernate 用作 ORM,并且此行为在 Hibernate 文档中得到了完美的描述。在Transaction chapter

通过 Session(也是事务范围的缓存),Hibernate 提供可重复的读取以通过标识符和实体查询进行查找,而不是报告返回标量值的查询。

IBatis 也是如此

MyBatis 使用两个缓存:一个本地缓存和一个二级缓存。每个 创建新会话的时间 MyBatis 创建一个本地缓存并 将其附加到会话。在会话中执行的任何查询都将 存储在本地缓存中,以便进一步执行相同的查询 使用相同的输入参数不会命中数据库。本地的 缓存在更新、提交、回滚和关闭时被清除。

【讨论】:

  • 谢谢大家。我感谢您的解释。
猜你喜欢
  • 2018-03-24
  • 2023-04-02
  • 2014-08-31
  • 2012-06-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-27
相关资源
最近更新 更多