Spring数据 - 在“手动”后端查询更新后刷新实体

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring数据 - 在“手动”后端查询更新后刷新实体相关的知识,希望对你有一定的参考价值。

让我们假设有这种情况:

我们有以标准方式配置的弹簧数据,有一个Respository对象,一个Entity对象,一切运行良好。

现在,对于一些复杂的动机,我必须直接使用EntityManager(或JdbcTemplate,无论是低于spring数据的任何级别)来更新与我的Entity相关联的表,使用本机sql查询。所以我没有使用Entity对象,而是简单地在我用作实体的表上手动进行数据库更新(更准确地说是从中获取值的表,请参阅下一行)。原因是我必须将我的spring-data Entity绑定到一个mysql视图,该视图使UNION成为多个表,而不是直接到我需要更新的表。

会发生什么:

在一个功能测试中,我称之为“手动”更新方法(在创建mysql视图的表上)(通过实体管理器)和如果我做一个简单的Respository.findOne(objectId)我得到旧对象(没有更新一个)。我要打电话给Entitymanager.refresh(object)来获取更新的对象。

为什么?

有没有办法在spring-data中“同步”(开箱即用)对象(或强制刷新一些)?还是我要求奇迹?我不讽刺,但也许我不是那么专家,也许(或可能)是我的无知。如果是这样,请解释我为什么和(如果你想)分享一些关于这个惊人框架的高级知识。

答案

如果我做一个简单的Repository.findOne(objectId)我得到旧对象(没有更新)。我要调用Entitymanager.refresh(object)来获取更新的对象。

为什么?

第一级缓存在会话期间处于活动状态。除非有理由返回数据库,否则将从第一级缓存中检索先前在会话上下文中检索的任何对象实体。

SQL更新后是否有理由返回数据库?好吧,正如Pro JPA 2关于批量更新语句(通过JPQL或SQL)的说明(p199):

开发人员在使用这些[批量更新]语句时要考虑的第一个问题是持久性上下文未更新以反映操作的结果。批量操作作为SQL针对数据库发布,绕过持久性上下文的内存中结构。

这就是你所看到的。这就是为什么你需要调用refresh来强制从数据库重新加载实体,因为持久化上下文不知道任何潜在的修改。

本书还提到了有关使用Native SQL语句(而不是JPQL批量更新)的以下内容:

■注意不应对实体映射的表执行本机SQL更新和删除操作。 JP QL操作告诉提供程序必须使缓存的实体状态无效,以便与数据库保持一致。本机SQL操作绕过此类检查,并且可能很快导致内存缓存相对于数据库过期的情况。

基本上,如果您配置了二级缓存,则通过本机SQL语句更新当前缓存中的任何实体可能会导致缓存中的陈旧数据。

另一答案

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

这是一个样本测试

@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());
    }

}

以上是关于Spring数据 - 在“手动”后端查询更新后刷新实体的主要内容,如果未能解决你的问题,请参考以下文章

JAVAweb如何实现在一个查询好的页面实现更新以及删除操作,删除操作要求在此页面进行并删除后刷新页面

直接从querydsl更新数据时如何刷新Spring JPA?

使用每日更新的Access表自动刷新SQL Server后端

PowerQuery在Excel中手动刷新数据连接

PowerQuery在Excel中手动刷新数据连接

内联更新后,Kendo Treelist重新加载/刷新