Spring boot、Spring data JPA并发访问

adi*_*ool 7 concurrency jpa spring-transactions spring-data-jpa spring-boot

我正在尝试使用 Spring boot 和 Spring data JPA 创建一个 Restful API 来执行 CRUD 操作。数据库将是Oracle关系数据库。现在进行并发访问,如果我们仅使用@Transactional的Spring事务,是否可以满足我们并发CRUD操作的目的。

我看到有JPA乐观和悲观锁定策略版本专栏。我的具体问题是,对于并发 CRUD 操作,我们是否需要 Spring 事务和 JPA 锁定策略?或者只相应地配置 Spring 事务就足够了?

Cep*_*pr0 12

尝试从以下简单的方法开始,IMO 在许多情况下都适用:乐观锁定Spring Retry

1)向您的实体添加version注释的属性@Version(例如,您可以在基本抽象实体类中执行此操作,以简化流程):

@Entity
public class MyEntity {

    @Id
    @GeneratedValue
    private Long id;

    @Version
    private Long version;

    // other stuff
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,例如,当您更新实体时,Hibernate 将使用version更新查询的条件子句中属性的当前值,并增加该值以存储实体。例如某些服务的代码:

@Transactional
public Optional<MyEntity> update(Long id, MyEntity source) {
    return myEntityRepository
           .findById(id)
           .map(target -> mapper.updateEntity(source, target));
}
Run Code Online (Sandbox Code Playgroud)

将生成以下 SQL 查询:

1. select * from my_entities where id = ?; 
2. update my_entities set ..., version = <version value from query #1> + 1 where id = ? and version = <version value from query #1>;
Run Code Online (Sandbox Code Playgroud)

因此,如果另一个并发进程设法首先更新此实体,那么您的方法将失败并出现异常 (OptimisticLockException)。

2)要管理该方法中的异常,请@Retryable向其添加注释(以及@EnableRetry您的配置或应用程序类上的注释):

@Retryable(maxAttempts = 2)
@Transactional
public Optional<MyEntity> update(Long id, MyEntity source) {
    // ...
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,如果该方法出现异常,它将在新事务中再次调用以重复操作。

附加信息:


小智 1

乐观锁是JPA的默认策略。乐观锁可用于大多数应用程序。乐观锁更加容易和高效。在提交事务之前需要知道冲突的情况下需要使用悲观锁。

所以你不需要配置锁定策略。