我有以下服务:
@Service
public class CamelService {
@Transactional
public aCamelThing() {
Camel camel = this.camelRepository.findOne(1);
System.out.println(camel.getCamelName()); // prints "normalCamel"
// simple hql set field 'camelName'
int res = this.camelRepository.updateCamelName(1,"superCamel!");
Camel camelWithNewName = this.camelRepository.findOne(1);
System.out.println(camelWithNewName .getCamelName()); // prints "normalCamel" ?!?!?
}
}
任何想法如何实现第二个println打印的目标:“superCamel!” ? (将第二次调用与新交易分开并不理想)。
答案 0 :(得分:15)
你认为这个有效的原因非常简单:JPA被定义为以这种方式工作。
我假设您触发了updateCamelName(…)
的更新查询。 JPA规范声明了以下更新和删除操作:
持久性上下文与批量更新或删除的结果不同步。
执行批量更新或删除操作时应该小心,因为它们可能导致数据库与活动持久性上下文中的实体之间出现不一致。通常,批量更新和删除操作应仅在新持久性上下文中的事务中执行,或者在获取或访问其状态可能受此类操作影响的实体之前执行。
这意味着,如果您需要查看此类操作的更改,则需要执行以下操作:
EntityManager
。 Spring Data JPA的@Modifying
注释的clearAutomatically
标记默认为false
。如果将其设置为true,则调用查询方法将自动清除EntityManager
(顾名思义。请谨慎使用,因为它会有效地删除尚未刷新到数据库的所有待处理更改呢!的EntityManager
重新获取实体的新实例。在存储库上调用findOne(…)
似乎是一种合理的方法,因为这大致转换为{ {1}}。请注意,这可能仍会影响在持久性提供程序上配置的二级缓存。解决这个问题最安全的方法是 - 正如规范建议的那样 - 仅将更新查询用于批量操作并回退到加载实体,更改,合并"默认接近。