Skip to content

Spring多线程事务 能否保证事务的一致性

在多线程环境下,Spring事务管理默认情况下无法保证全局事务的一致性。这是因为Spring的本地事务管理是基于线程,每个线程都有自己的独立事务。

202512062334459ec0921d6.png

Spring的事务管理通常将事务信息存储在ThreadLocal中(为了实现事务传播),这意味着每个线程只能拥有一个事务。这确保了在单个线程内的数据库操作处于同一个事务中,保证了原子性。

可以通过如下方案进行解决:

- **编程式事务:** 为了在多线程环境中实现事务一致性,您可以使用编程式事务管理。这意味着您需要在代码中显式控制事务的边界和操作,确保在适当的时机提交或回滚事务。
- **分布式事务:** 如果您的应用程序需要跨多个资源(例如多个数据库)的全局事务一致性,那么您可能需要使用分布式事务管理(如2PC/3PC TCC等)来管理全局事务。这将确保所有参与的资源都处于相同的全局事务中,以保证一致性。

总之,在多线程环境中,Spring的本地事务管理需要额外的协调和管理才能实现事务一致性。这可以通过编程式事务、分布式事务管理器或二阶段提交等方式来实现,具体取决于您的应用程序需求和复杂性。

编程式事务示例

其核心是通过TransactionTemplate自己控制事务回滚来完成多线程事务

java

    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Autowired  
    private TransactionTemplate transactionTemplate;

    private final ExecutorService executorService = Executors.newFixedThreadPool(2);

    // 主线程事务方法  
    public void mainThread() throws Exception {  
        transactionTemplate.execute(new TransactionCallback<Void>() {
            @Override  
            public Void doInTransaction(TransactionStatus status) {
                try {  
                    // 主事务的数据库操作  
                    jdbcTemplate.execute("INSERT INTO `test`.`user` (`age`, `name`, `city`) VALUES (18, 'xushu', 'BeiJin');");

                    // 启动子线程并执行子事务
                    Future<Void> future = executorService.submit(() -> {
						jdbcTemplate.execute("INSERT INTO `test`.`user` (`age`, `name`, `city`) VALUES (18, 'xushu', 'BeiJin');");
                        return null;
                    });

                    // 等待子线程完成
                    future.get();
                } catch (Exception e) {  
                    // 回滚主事务  
                    status.setRollbackOnly();  
                    throw new RuntimeException(e);  
                }  
                return null;  
            }  
        });  
    }

分布式事务2PC实例:

分布式事务如果不懂,可以先去了解:

分布式事务有哪些常见的实现方案

这里介绍2pc手动实现方式:

java
public class TwoPhaseCommitService {
    @Autowired
    private final PlatformTransactionManager transactionManager;
    private final ExecutorService executor = Executors.newCachedThreadPool();
 

    public void executeMultiThreadTransaction() throws Exception {
        List<Future<Boolean>> futures = new ArrayList<>();
        List<TransactionStatus> transactionStatuses = new ArrayList<>();

        // 阶段一:提交所有子线程事务操作
        for (int i = 0; i < 5; i++) {
            Future<Boolean> future = executor.submit(() -> {
                TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
                TransactionStatus status = transactionManager.getTransaction(null);
                transactionStatuses.add(status);

                try {
                    // 执行业务操作(例如数据库更新)
                    transactionTemplate.execute(new TransactionCallbackWithoutResult() {
                        @Override
                        protected void doInTransactionWithoutResult(TransactionStatus status) {
                            // 数据库操作代码
                        }
                    });
                    return true; // 阶段一成功
                } catch (Exception e) {
                    transactionManager.rollback(status);
                    return false; // 阶段一失败
                }
            });
            futures.add(future);
        }

        // 检查所有子线程是否成功
        boolean allSuccess = futures.stream().allMatch(f -> {
            try {
                return f.get();
            } catch (InterruptedException | ExecutionException e) {
                return false;
            }
        });

        // 阶段二:统一提交或回滚
        if (allSuccess) {
            transactionStatuses.forEach(transactionManager::commit);
        } else {
            transactionStatuses.forEach(transactionManager::rollback);
        }
    }
}

更新: 2025-04-02 13:48:56
原文: https://www.yuque.com/tulingzhouyu/db22bv/qpaoo8nabf8490cn