spring数据“手动”后台查询更新后刷新实体

xxls0lw8  于 2021-07-15  发布在  Java
关注(0)|答案(3)|浏览(357)

这个问题在这里已经有答案了

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,也许(或者可能)是我的无知。如果是的话,请向我解释为什么,并(如果你想)分享一些关于这个惊人框架的高级知识。

dsf9zpds

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语句更新缓存中当前的任何实体都可能导致缓存中的过时数据。

58wvjzkj

58wvjzkj2#

在spring boot jparepository中:
如果修改查询更改了持久性上下文中包含的实体,那么这个上下文就过时了。
以便从数据库中获取具有最新记录的实体。
使用@modifying(clearautomatically=true)
@修改注解具有clearautomatically属性,该属性定义在执行修改查询后是否应清除底层持久性上下文。
例子:

@Modifying(clearAutomatically = true)
        @Query("UPDATE NetworkEntity n SET n.network_status = :network_status WHERE n.network_id = :network_id")
    int expireNetwork(@Param("network_id") Integer network_id,  @Param("network_status") String network_status);
kgsdhlau

kgsdhlau3#

根据您描述的使用方式,从repo获取应该检索更新的对象,而无需刷新对象,只要使用实体管理器合并的方法具有@transactional属性
这是一个样本测试

@DirtiesContext(classMode = ClassMode.AFTER_CLASS)
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = ApplicationConfig.class)
@EnableJpaRepositories(basePackages = "com.foo")
public class SampleSegmentTest {

    @Resource
    SampleJpaRepository segmentJpaRepository;

    @PersistenceContext
    private EntityManager entityManager;

    @Transactional
    @Test
    public void test() {
        Segment segment = new Segment();
        ReflectionTestUtils.setField(segment, "value", "foo");
        ReflectionTestUtils.setField(segment, "description", "bar");

        segmentJpaRepository.save(segment);

        assertNotNull(segment.getId());
        assertEquals("foo", segment.getValue());
        assertEquals("bar",segment.getDescription());

        ReflectionTestUtils.setField(segment, "value", "foo2");
        entityManager.merge(segment);

        Segment updatedSegment = segmentJpaRepository.findOne(segment.getId());
        assertEquals("foo2", updatedSegment.getValue());
    }

}

相关问题