JPA 锁定 PESSIMISTIC_WRITE 和 FEW 事务

Posted

技术标签:

【中文标题】JPA 锁定 PESSIMISTIC_WRITE 和 FEW 事务【英文标题】:JPA locks PESSEMISTIC_WRITE and FEW transactions 【发布时间】:2021-02-06 17:51:15 【问题描述】:

我在我的存储库方法上使用 PESSEMSTIC_WRITE 锁。这就是锁定我的对象直到交易结束。但是,我遇到了一个问题,在一个端点内,控制器-> 服务-> 我开始事务然后我需要更新我的对象并将消息发送到 kafka,之后我需要在此方法中再次更新我的对象并发送到 kafka .因此,因为它是一个事务,所以更改仅在缓存中本地起作用。但是我需要保存在数据库中然后发送到 kafka,然后再次更改我的对象并保存到数据库并发送到 kafka 消息,我不能使用 REQUIRES_NEW 并以任何方式创建新事务,因为我的对象被锁定。那么我该如何处理呢? 这个锁在我的项目的许多部分中用于修复并行事务。

【问题讨论】:

我对您要解决的实际问题感到困惑。你是什​​么意思'我需要保存在数据库中然后发送到kafka'?当您的对象被写锁锁定时,没有其他人可以读取相应的行,此时您是否保存到数据库有什么关系?在锁被释放之前,这些更改将不可见 好吧,但是我需要这个杀手在锁定对象上保存两次,我认为业务有问题。 【参考方案1】:

您应该创建将协调流程的新服务。这样你就可以在第二次操作中再次获得同样的悲观锁。

@Service
class OrchestratorService 
   ...

   void executeFlow() 
       someService.executeFirstOperationAndSendKafkaEvent()
       someService.executeSecondOperationAndSendKafkaEvent()       
   

@Service
class SomeService 

   @Transactional(REQUIRES_NEW)
   void executeFirstOperationAndSendKafkaEvent() 
       // any lock which obtained inside this method will be released once this method finishes
       ...       
   

   @Transactional(REQUIRES_NEW)
   void executeSecondOperationAndSendKafkaEvent() 
       // any lock which obtained inside this method will be released once this method finishes
       ...       
   

还有一个更重要的方面值得一提——发送 kafka 事件不是事务性的。 @Transactional 只保证对数据源所做的更改将是事务性的(在本例中为数据库)。因此,以下情况是可能的:

如果在事务范围内发送事件,则在成功发送 kafka 事件后可以回滚事务 如果在事务提交之外发送事件,成功提交事务后事件发送可能会失败

由于这种性质,最好将流程分成几个阶段:

    在 DB 中应用业务更改并在 DB 中存储一个应该发送 kafka 事件的标志,但尚未完成, TX 范围外向 kafka 发送事件 在新的 TX 中更改事件已发送的标志,或在发送事件期间发生错误时安排重试。

【讨论】:

谢谢,我使用了类似的代码。我使服务 OrchestratorService 不是事务性的,然后 SomeService 使事务性,所以每次我得到一个新的事务。

以上是关于JPA 锁定 PESSIMISTIC_WRITE 和 FEW 事务的主要内容,如果未能解决你的问题,请参考以下文章

Spring Data JPA / Hibernate中锁的范围是什么?

带有 PESSIMISTIC_WRITE 锁的 REPEATABLE_READ 隔离级别

PostgreSQl 正确锁定新实体的创建

Spring data Jpa,Mybatis,读写锁,@Lock 使用

如何在spring data jpa查询中指定@lock超时?

JPA 和乐观锁定模式