简体   繁体   English

更新和返回弹簧数据 JPA 中的数据

[英]update and return data in spring data JPA

For concurrency purpose, I have got a requirement to update the state of a column of the database to USED while selecting from AVAILABLE pool.出于并发目的,我需要在从 AVAILABLE 池中进行选择时将数据库列的状态更新为 USED。

I was thinking to try @Modifying , and @Query (query to update the state based on the where clause)我正在考虑尝试@Modifying@Query (根据 where 子句更新状态的查询)

It is all fine, but this is an update query and so it doesn't return the updated data.一切都很好,但这是一个更新查询,因此它不会返回更新的数据。

So, is it possible in spring data, to update and return a row, so that whoever read the row first can use it exclusively.那么,是否可以在 spring 数据中更新并返回一行,以便先读取该行的人可以独占使用它。

My update query is something like UPDATE MyObject o SET o.state = 'USED' WHERE o.id = (select min(id) from MyObject a where a.state='AVAILABLE') , so basically the lowest available id will be marked used.我的更新查询类似于UPDATE MyObject o SET o.state = 'USED' WHERE o.id = (select min(id) from MyObject a where a.state='AVAILABLE') ,所以基本上最低的可用 id 将被标记使用。 There is a option of locking, but these requires exceptional handling and if exception occur for another thread, then try again, which is not approved in my scenario有一个锁定选项,但这些需要特殊处理,如果另一个线程发生异常,则重试,这在我的场景中不被批准

I suggest to use multiple transactions plus Optimistic Locking.我建议使用多个事务加上乐观锁。 Make sure your entity has an attribute annotated with @Version .确保您的实体有一个用@Version注释的属性。

In the first transaction load the entity, mark it as USED , close the transaction.在第一个事务中加载实体,将其标记为USED ,关闭事务。

This will flush and commit the changes and make sure nobody else touched the entity in the mean time.这将刷新并提交更改,并确保在此期间没有其他人触及该实体。

In the second transaction you can no do whatever you want to do with the entity.在第二个事务中,您无法对实体执行任何操作。

For these small transactions I find it clumsy to move them to separate methods so I can use @Transactional .对于这些小事务,我发现将它们移到单独的方法中很笨拙,因此我可以使用@Transactional I therefore use the TransactionTemplate instead.因此,我改用TransactionTemplate

You need to explicitly declare a transaction to avoid other transactions being able to read the values involved until it's commited.您需要明确声明一个事务,以避免其他事务在提交之前能够读取所涉及的值。 The level with best performance allowing it is READ_COMMITED , which doesn't allow dirty reads from other transactions (suits your case).允许它的最佳性能级别READ_COMMITED ,它不允许来自其他事务的脏读(适合您的情况)。 So the code will look like this:所以代码看起来像这样:

Repo:回购:

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

Service:服务:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM