gpt4 book ai didi

java - 如何在 Spring 中处理具有并发访问的事务

转载 作者:行者123 更新时间:2023-11-30 10:51:04 24 4
gpt4 key购买 nike

我有一种方法的服务:

    @Service
public class DefaultTestService implements TestService {
private static final Logger LOGGER = Logger.getLogger(DefaultTestService.class);
@Autowired
private TestRepository testRepository;

@Transactional(readOnly = false, isolation = Isolation.SERIALIZABLE)
@Override
public void incrementAndGet(Long testModelId) {
LOGGER.debug("Transaction is active: " + TransactionSynchronizationManager.isActualTransactionActive());
final TestModel tm = testRepository.findOne(testModelId);
if (tm != null) {
LOGGER.debug("Updated " + testModelId + " from value: " + tm.getValue());
tm.setValue(tm.getValue() + 1);
testRepository.save(tm);
} else {
LOGGER.debug("Saved with id: " + testModelId);
final TestModel ntm = new TestModel();
ntm.setId(testModelId);
testRepository.save(ntm);
}
}
}

我正在使用带有 testModelId = 1L 参数的 2 个并行调用配置运行 Gatling。由于这些调用,我收到错误消息:

org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "test_model_pkey"

从日志中可以看到,有两次调用同时进入了这个方法,并且每次都打印了日志

"Saved with id: 1"
"Saved with id: 1"

我假设在此方法上添加事务注释会阻止 testRepository.findOne(testModelId) 行中的一个调用,直到其他调用完成其执行,但正如我从日志中看到的那样,它正在运行以不同的方式。

所以我的问题是,当出现并发访问时,事务在这种情况下是如何工作的?我该如何处理这种并发访问的情况?

最佳答案

事务意味着在事务边界内执行的持久对象的所有修改将:

  • 在事务结束时提交(即所有修改都保存在数据库中)
  • 在事务结束时回滚(即没有的修改保留在数据库中)就这样。

交易在这种情况下如何运作?

2 个线程中的一个到达事务末尾并成功提交。另一个线程到达事务末尾,由于违反约束而未能提交,因此第二个事务终止于“回滚”状态。

为什么 findOne 在第二笔交易中没有被阻塞?

仅仅是因为,尽管有 SERIALIZABLE 事务级别,但没有要锁定的行。 findOne 在两个事务中都没有返回任何结果,也没有任何东西被锁定(当然,如果第一个事务在第二个事务执行之前提交 findOne :这是另一回事)。

在您的特定情况下如何处理并发事务(即插入新行时违反 PK 约束)?

最常见的策略是让数据库将 id 分配给新行 - 在序列的帮助下 -

(作为实验,您可以尝试将隔离级别设置为 READ_UNCOMMITED,以便第二个事务可以从第一个事务读取未提交的更改。我不确定您是否注意到任何差异,因为如果 findOne 在第二个事务在 testRepository.save(ntm); 之前执行,从第一个事务开始它仍然不会返回任何结果)

一般如何处理并发修改引起的事务回滚?

这实际上取决于您的用例。基本上你可以选择:

  • 捕获异常并“重试”操作。
  • 向调用方抛出异常(可能向用户显示一条温和的错误消息)。

请注意,如果事务以回滚状态终止:事务期间修改的持久对象图不会恢复到其原始状态。

请注意,使用隔离级别 SERIALIZABLE 会导致巨大的性能问题,通常仅用于关键和偶尔的事务。

关于java - 如何在 Spring 中处理具有并发访问的事务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34832758/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com