这个问题在这里已经有答案了:
spring data jpa update@query不更新(5个答案)
去年关门了。
假设有这样的情况:
我们用标准方式配置了spring数据,有一个 Respository
对象,一个 Entity
对象,一切正常。
现在对于一些复杂的动机我必须直接使用 EntityManager
(或 JdbcTemplate
,以更新与我的 Entity
,使用本机sql查询。所以我没有使用 Entity
对象,但只需在用作实体的表上手动执行db更新(更正确的说法是从中获取值的表,请参阅下一行)。原因是我必须绑定spring数据 Entity
到一个mysql视图,使多个表合并,而不是直接到我需要更新的表。
结果是:
在一个功能测试中,我调用前面描述的“手动”更新方法(在创建mysql视图的表上)(通过entitymanager),如果我做了一个简单的 Respository.findOne(objectId)
我得到旧的对象(不是更新的)。我得打个电话 Entitymanager.refresh(object)
获取更新对象。
为什么?
有没有办法在spring数据中“同步”(开箱即用)对象(或者强制刷新)?还是我在祈求奇迹?我不是讽刺,但也许我不是那么Maven,也许(或者可能)是我的无知。如果是的话,请向我解释为什么,并(如果你想)分享一些关于这个惊人框架的高级知识。
3条答案
按热度按时间dsf9zpds1#
如果我做一个简单的respository.findone(objectid),我会得到一个旧对象(不是更新的)。我必须调用entitymanager.refresh(object)来更新对象。
为什么?
一级缓存在会话期间处于活动状态。以前在会话上下文中检索到的任何对象实体都将从一级缓存中检索,除非有理由返回数据库。
是否有理由在sql更新后返回数据库?正如pro jpa2(p199)中关于批量更新语句(通过jpql或sql)的注解所示:
开发人员在使用这些[bulk update]语句时要考虑的第一个问题是,持久性上下文没有更新以反映操作的结果。批量操作作为sql针对数据库发出,绕过持久性上下文的内存结构。
这就是你看到的。这就是为什么需要调用refresh来强制从数据库中重新加载实体,因为持久性上下文不知道任何潜在的修改。
本书还注意到以下关于使用本机sql语句(而不是jpql批量更新)的内容:
■ 警告:不应在实体Map的表上执行本机sql更新和删除操作。jp-ql操作告诉提供者,为了与数据库保持一致,哪些缓存实体状态必须无效。本机sql操作会绕过此类检查,并很快导致inmemory缓存相对于数据库过期的情况。
基本上,如果配置了第二级缓存,那么通过本机sql语句更新缓存中当前的任何实体都可能导致缓存中的过时数据。
58wvjzkj2#
在spring boot jparepository中:
如果修改查询更改了持久性上下文中包含的实体,那么这个上下文就过时了。
以便从数据库中获取具有最新记录的实体。
使用@modifying(clearautomatically=true)
@修改注解具有clearautomatically属性,该属性定义在执行修改查询后是否应清除底层持久性上下文。
例子:
kgsdhlau3#
根据您描述的使用方式,从repo获取应该检索更新的对象,而无需刷新对象,只要使用实体管理器合并的方法具有@transactional属性
这是一个样本测试