当前位置:网络安全 > Spring如何保证多线程环境下的事务一致性

Spring如何保证多线程环境下的事务一致性

  • 发布:2023-10-07 13:10

问题是现在

我先把问题抛出来,大家就明白这篇文章要解决什么样的业务痛点了:

public void removeAuthorityModuleSeq(整数authorityModuleId,IAuthorityService iAuthorityService,IRoleAuthorityService iRoleAuthorityService){
//1.查询出当前资源模块下的所有资源,查询后将被删除
  deleteAuthoritiesOfCurrentAuthorityModule(authorityModuleId, iAuthorityService, iRoleAuthorityService);
//2.查询出当前资源模块下的所有子模块,递归查询,并删除 Finished 完成所有子模块资源后,删除所有子模块,最后删除当前资源模块。 ); 3 // 3.删除当前资源模块
RemoveByid (authorityModuleId);
}

如果我想并行执行步骤1和步骤2,然后保证步骤1和步骤2执行成功,然后执行步骤3,等到步骤3执行完毕,然后提交所有交易,如何实现这个要求?

如何解决异步执行

上述需求的第一点是:如何让任务异步并行执行,如何实现二进制依赖?

说起异步执行,很多朋友首先想到spring提供的@Async注解,但是Spring提供的异步任务执行能力还不足以解决我们当前的需求。

@Async注解的原理很简单,就是扫描IOC中的bean,代理方法上标有@Async注解的bean。代理的核心是添加一个MethodInterceptor,即AsyncExecutionInterceptor,这个方法拦截器负责将方法的实际执行打包成任务并放入线程中执行池。

让我们首先使用CompletableFuture来完成我们的第一步要求:

public void removeAuthorityModuleSeq(整数authorityModuleId,IAuthorityService iAuthorityService,IRoleAuthorityService iRoleAuthorityService) {
CompletableFuture.runAsync(()->{
//两个任务并行执行
                                                                                            “deleteAuthoritiesOfCurrentAuthorityModule(authorityModuleId, iAuthorityService, iRoleAuthorityService),executor);
“CompletableFuture?
//等待两个并行任务完成后再执行最后一步
           CompletableFuture.allOf(future1, future2).thenRun(()->removeById(authorityModuleId));

多线程环境下如何保证事务一致性

我们已经完成了任务的异步执行,那么如何保证多线程环境下的事务一致性呢?

public void removeAuthorityModuleSeq(整数authorityModuleId,IAuthorityService iAuthorityService,IRoleAuthorityService iRoleAuthorityService) {
CompletableFuture.runAsync(()->{
//两个任务并行执行
                                                                               ‐ ‐ ‐ ‐ ‐        “ deleteAuthoritiesOfCurrentAuthorityModule(authorityModuleId, iAuthorityService, iRoleAuthorityService),executor);
“ CompletableFuture ?
//等待两个并行任务完成后再执行最后一步
            CompletableFuture.allOf(future1, future2).thenRun(()->removeById(authorityModuleId));

说到Spring环境下的事务控制,大家第一反应就是使用@Transactional注解来解决问题,但在这里显然不行。为什么不起作用?

我简单总结一下Spring事务的实现原理:

事务王国评论

交易管理大致分为三个流程:交易创建、交易执行、交易结束

交易创建涉及到一些属性的配置,例如:

  • 事务隔离级别
  • 事务的传输行为
  • 交易超时
  • 是否是只读事务

由于涉及到的属性较多,且后期可能会扩展,所以这些属性必须通过类进行封装,对应Spring中的TransactionDefinition

有了交易相关的属性定义,我们可以使用TransactionDefinition来创建交易。在 Spring 中,本地事务由 PlatformTransactionManager 管理,事务创建也是由 PlatformTransactionManager 负责提供:

 TransactionStatus getTransaction(@Nullable TransactionDefinition 定义)
抛出 TransactionException

如果我们想要跟踪事务的状态,比如:事务完成、事务回滚等,那么我们需要一个贯穿当前事务执行过程的事务状态类。在 Spring 中,TransactionStatus 负责此操作。

对于常见的数据源,通常需要记录的事务状态如下:

  • 当前交易是否为新交易
  • 当前交易是否结束
  • 当前事务是否需要回滚(通过标记来判断,所以我也可以在业务流程中手动将标记设置为true,让事务无异常地回滚)
  • 当前事务是否设置了回滚点(savePoint)

一笔交易的执行过程就是具体业务代码的执行过程,这里不再赘述。

事务结束分为两种情况:事务需要回滚或者事务正常提交。如果事务回滚,还需要判断TransactionStatus中的savePoint是否已经设置。

交易实现方法回顾

Spring中有两种常见的事务实现方式:编程式和声明式。

相关文章