Spring中多线程事务处理

Spring中多线程事务处理

在青芒第三次迭代时,一个活动模块需要同时处理多个实体的业务,而彼此业务间没有关联,但存在事务性,考虑再三,决定尝试使用多线程处理多个业务

在了解了Spring事务处理之后,使用 编程式事务处理 更为灵活,由于有多个线程,而每个线程对应一个数据库连接,所以在多线程环境中,事务不止一个,同理事务状态也不止一个,因此这里的解决办法就是 将所有线程的事务状态保存到一个同步集合(多线程环境下使用同步集合,保证线程安全),若某个线程出现错误,遍历所有线程的事务状态,循环回滚

编程式事务步骤

步骤:(使用PlatformTransactionManager)

  1. 定义事务属性

    1
    DefaultTransactionDefinition dt = new DefaultTransactionDefinition();
  2. 设置事务传播行为

    1
    dt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
  3. 获得事务状态

    1
    TrasactionStatus status = platformTransactionManager.getTransaction(dt);
  4. 数据库操作

    1
    2
    // ...一些业务处理
    platformTransactionManager.commit(status); // 记得一定要手动提交!手动提交!手动提交!
  5. 若有异常,回滚

    1
    2
    3
    4
    5
    6
    7
    // 上面数据操作应在try...catch里,完整代码
    try {
    // ...一些业务处理
    platformTransactionManager.commit(status); // 记得一定要手动提交!手动提交!手动提交!
    } catch(Exception e) {
    platformTransactionManager.rollback(status);
    }

实际项目运用

上面展示了实现Spring编程式事务的一些基本步骤,接下来展示如何应用在青芒项目中多线程事务处理

  1. 定义 TransactionStatus的同步集合

主程序

注意上图的 List transactionStatuses = Collections.synchronizedList(new ArrayList());

  1. 启动线程

    启动线程

使用statusList将当前的事务状态放进同步集合里,每当业务处理中有出错信息,则回滚每个线程中的事务,同时抛出异常。

注意:在子线程里的异常是不能被主线程捕获,如果子线程发生异常,而内部不处理,则会逃逸到控制台,所以子线程的异常要在子线程自己内部处理。这时要想将异常被主线程捕获,可以使用比较多的方法,如UncaughtExceptionHandler,Futrue等等,这里使用线程框架 Executors + Future去将子线程发生的异常捕获出来。

总结

在多线程中保证事务,在Spring里可以利用同步集合 + 编程式事务实现,同时要想获取子线程的事务,可以使用线程框架Executors的submit + Futrue获取结果,遍历结果,可以获得错误信息。

参考资料

  1. 多线程异常与事务
-------------本文结束感谢您的阅读-------------