尝试以下简单方法开始,在我看来,它在许多情况下都是合适的:
使用乐观锁和
Spring Retry。
1)向您的实体中添加标记为
@Version
的
version
属性(例如,您可以在基础抽象实体类中这样做,以简化该过程):
@Entity
public class MyEntity {
@Id
@GeneratedValue
private Long id;
@Version
private Long version;
}
在这种情况下,例如,当您更新实体时,Hibernate将使用version
属性的当前值在更新查询的条件子句中,并将该值递增以将实体存储在其中。例如,下面是某些服务的代码:
@Transactional
public Optional<MyEntity> update(Long id, MyEntity source) {
return myEntityRepository
.findById(id)
.map(target -> mapper.updateEntity(source, target));
}
将生成以下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>;
如果另一个并发进程首先成功更新此实体,则您的方法将失败并引发异常(OptimisticLockException)。
2)为了管理该方法中的异常,请向其中添加@Retryable
注释(并在配置或应用程序类上添加@EnableRetry
注释):
@Retryable(maxAttempts = 2)
@Transactional
public Optional<MyEntity> update(Long id, MyEntity source) {
}
在这种情况下,如果该方法出现异常,它将会在新的事务中再次被调用以重复操作。
额外信息: