【问题标题】:Spring @Transactional for creating thread safe logicSpring @Transactional 用于创建线程安全逻辑
【发布时间】:2021-05-11 08:36:05
【问题描述】:

我有一个服务方法,我通过 ID 从数据库中请求一个实体。如果实体具有paid == false 属性,我将其设置为true 并做一些事情。如果paid==true 它只是返回。

@Override
@Transactional(rollbackFor={ServiceException.class})
public void handleIntentSucceeded(PaymentIntent intent) throws ServiceException {
   LOGGER.trace("handleIntentSucceeded({})", intent);

   CreditCharge charge = transactionRepository.findByPaymentIntentId(intent.getId());

   if(charge.getPaid()) {
      return;


   // do some stuff          

   charge.setPaid(true);
   transactionRepository.save(charge);

}

现在如果有多个请求同时具有相同的intent,这个方法将不再一致,因为例如第一个请求接收到chargepaid==false,所以它会“一些事情”,如果第二个请求在第一个请求使用paid==true 保存费用之前到达此方法,即使第一个请求已经这样做,它也会做“一些事情”。这是一个正确的结论吗?

为了确保一次只能处理一个请求,以避免“某些事情”被多次执行,我可以将 Transactional 设置为@Transactional(isolation = Isolation.SERIALIZABLE)。这样,任何请求只有在请求之前提交过 Transactional 时才能处理此方法/事务。

这是最好的方法还是有更好的方法?

【问题讨论】:

  • 不要要求最好的方法——它是基于意见的,不会把你带到任何地方。让它发挥作用,看看它是否需要改进,然后改进它——这就是你学习的方式。即使事务可以防止脏读等,事务也不是真正关于线程安全的——看看这里stackoverflow.com/questions/6477574/…
  • 如果你想要更好的答案,你应该问“有没有比这个更好的方法?”。并参考这个问题以更好地理解@Transactional stackoverflow.com/questions/1079114/…的用例
  • 定义“一致”。我们不知道您的业务需求是什么。如果你的意思是如果另一个事务知道Charge.paid同时已经更新,那么你不需要SERIALIZABLEREPEATABLE_READ就足够了。如果您的意思是一个事务开始应该阻止所有其他事务做同样的事情,那么您需要锁定您的实体以进行更新。

标签: java spring spring-boot jpa spring-data-jpa


【解决方案1】:

如上所述,一种解决方案是使用 OptimisticLocking。但是,OptimisticLockingException 会导致 http 请求失败。如果这是一个问题,您可以处理异常。

但是,如果您确定不会运行应用程序的多个实例并且对性能没有太大要求,或者您只是想稍后处理问题,直到使用“解决方法”,您可以制作方法synchronized (https://www.baeldung.com/java-synchronized)。这样,Java 运行时将确保该方法不能并行运行。

【讨论】:

    【解决方案2】:

    我可能会寻找一种乐观地锁定记录的方法(例如,使用某种更新计数器),以便只有更改 paid 属性的第一个并发事务才能成功完成。
    同时尝试修改同一实体的任何后续事务都会失败,并且它们在do some stuff 期间执行的操作将回滚。

    Optimistic vs. Pessimistic locking

    编辑:REPEATABLE_READ 隔离级别(正如其中一位 cmets 所建议的)也可能与乐观锁定类似; though this might depend on the implementation

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-12-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-21
      相关资源
      最近更新 更多