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

奥雷斯特

我有一种方法的服务:

    @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个并行调用config运行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)直到其他调用完成执行为止,但是从日志中可以看出,它以不同的方式工作。

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

本75

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

  • 在事务结束时提交(即所有修改都保留在数据库中)
  • 在交易(即年底rollbacked没有修改在DB被持久)这就是全部。

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

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

为什么findOne第二笔交易没有被冻结?

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

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

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

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

通常如何处理由于并发修改而导致的事务回滚?

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

  • 捕获异常并“重试”操作。
  • 向调用者抛出异常(可能向用户显示轻微的错误消息)。

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

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

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

在Spring数据中处理并发事务

在Spring-Boot中处理并发事务

如何在golang中处理并发日志?

如何在Spring中处理具有相同值但名称不同的按钮

如何在Spring Data REST中处理同一事务中的多个实体更新

具有并发访问的地图

如何在 itermWriterListener Spring 批处理中访问 stepExecution 内容

如何在事务中处理Spring休眠无锁获取的异常

如何在Spring事务中获取连接?

事务如何在 SQL Server 中具有多个 VALUES 的单个 INSERT 中工作

如何在组件方法中具有可访问的变量

在现有类中实现Spring事务处理

如何在ArangoDB中的事务中访问插入的文档的_id

Spring Web Flow-处理并发访问

Spring @事务和并发

Spring Integration中如何处理嵌套事务异常

如何在doobie中配置事务处理程序?

如何在Postgresql中处理分布式事务?

如何在 React Hooks 中处理多个状态的并发更新?

如何在并发环境中刷新访问令牌?

具有容器管理的事务的Singleton-EJB并发性

具有并发访问的Azure CloudAppendBlob错误

如何在Redux-Saga中以有限的并发和合理取消实现批处理任务?

如何在Spring Boot测试中强制事务提交?

如何在Spring Boot aop @Around函数中创建事务?

如何在Spring-MVC上处理具有多个参数的请求

如何在spring-security-javaconfig中添加访问拒绝处理程序

Spring事务在@Transactional方法中处理JMSTemplate

如何在graphQL中访问具有特定属性的所有元素?