在 Spring Data JPA 中更新和返回数据

Posted

技术标签:

【中文标题】在 Spring Data JPA 中更新和返回数据【英文标题】:update and return data in spring data JPA 【发布时间】:2016-07-28 14:43:43 【问题描述】:

出于并发目的,我需要在从 AVAILABLE 池中选择时将数据库列的状态更新为 USED。

我正在考虑尝试@Modifying@Query(根据where子句查询更新状态)

一切都很好,但这是一个更新查询,因此它不会返回更新后的数据。

那么,是否可以在spring数据中,更新并返回一行,让谁先读到该行,就可以独占使用。

我的更新查询类似于UPDATE MyObject o SET o.state = 'USED' WHERE o.id = (select min(id) from MyObject a where a.state='AVAILABLE'),所以基本上最低的可用 id 将被标记为已使用。有一个锁定选项,但是这些需要异常处理,如果另一个线程发生异常,然后再试一次,这在我的场景中是不被批准的

【问题讨论】:

在这种情况下你仍然需要锁定和异常处理,因为你还要如何防止并发请求访问同一行...... 标题中的问题见:***.com/questions/49690671/… 【参考方案1】:

您需要显式声明一个事务以避免其他事务在提交之前能够读取所涉及的值。允许它的level with best performance 是READ_COMMITED,它不允许从其他事务进行脏读(适合您的情况)。所以代码将如下所示:

回购:

@Repository
public interface MyObjectRepository extends JpaRepository<MyObject, Long> 

    @Modifying
    @Query("UPDATE MyObject o SET o.state = 'USED' WHERE o.id = :id")
    void lockObject(@Param("id") long id);

    @Query("select min(id) from MyObject a where a.state='AVAILABLE'")
    Integer minId();

服务:

@Transactional(isolation=Isolation.READ_COMMITTED)
public MyObject findFirstAvailable()
    Integer minId;
    if ((minId = repo.minId()) != null)
        repo.lockObject(minId);
        return repo.findOne(minId);
    
    return null;

【讨论】:

嗨,当我知道 id 但我不知道 id 时,您的解决方案将起作用。我的更新查询类似于“UPDATE MyObject o SET o.state = 'USED' WHERE o.id = (select min(id) from MyObject a where a.state='AVAILABLE')”,所以基本上最低的可用 id 将标记为已使用。有一个锁定选项,但这些需要异常处理,如果另一个线程发生异常,请再试一次,这在我的场景中是不被批准的。 刚刚编辑了我的答案。继续进行单个 Spring 事务,它将实现您想要的。无论如何,最好使用您在上面的评论中提供的详细信息更新您的问题。 它应该在多个服务器上工作,所以事务性不是一个解决方案。最后,我可能不得不选择乐观和悲观锁定,但前提是别无选择。 '它应该在多个服务器上工作,所以它不是一个解决方案'。实际上,这取决于您的数据库供应商和您的架构。事务在数据库级别工作,因此您的集群数据库必须保证它们被正确隔离。请根据您的全部要求编辑您的问题。【参考方案2】:

我建议使用多个事务加上乐观锁定。 确保您的实体具有使用@Version 注释的属性。

在第一个事务中加载实体,标记为USED,关闭事务。

这将刷新并提交更改,并确保同时没有其他人接触过实体。

在第二个事务中,你不能对实体做任何你想做的事情。

对于这些小事务,我发现将它们移动到单独的方法中很笨拙,因此我可以使用@Transactional。因此,我改用TransactionTemplate

【讨论】:

以上是关于在 Spring Data JPA 中更新和返回数据的主要内容,如果未能解决你的问题,请参考以下文章

当我不想更新实体时,Spring Data JPA 会更新它

处理 JPA 规范和 spring-data-jpa 时如何使用声明 Stream 作为返回类型

Spring Data Jpa新增和更新的问题。

从父类更新日期字段在 Spring Data Jpa 中不起作用

如何在 Spring Data 中漂亮地更新 JPA 实体?

如何在 Spring Data JPA 中获取 countQuery 返回的计数?