Spring中多线程事务处理
在青芒第三次迭代时,一个活动模块需要同时处理多个实体的业务,而彼此业务间没有关联,但存在事务性,考虑再三,决定尝试使用多线程处理多个业务
在了解了Spring事务处理之后,使用 编程式事务处理 更为灵活,由于有多个线程,而每个线程对应一个数据库连接,所以在多线程环境中,事务不止一个,同理事务状态也不止一个,因此这里的解决办法就是 将所有线程的事务状态保存到一个同步集合(多线程环境下使用同步集合,保证线程安全),若某个线程出现错误,遍历所有线程的事务状态,循环回滚
编程式事务步骤
步骤:(使用PlatformTransactionManager)
定义事务属性
1
DefaultTransactionDefinition dt = new DefaultTransactionDefinition();
设置事务传播行为
1
dt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
获得事务状态
1
TrasactionStatus status = platformTransactionManager.getTransaction(dt);
数据库操作
1
2// ...一些业务处理
platformTransactionManager.commit(status); // 记得一定要手动提交!手动提交!手动提交!若有异常,回滚
1
2
3
4
5
6
7// 上面数据操作应在try...catch里,完整代码
try {
// ...一些业务处理
platformTransactionManager.commit(status); // 记得一定要手动提交!手动提交!手动提交!
} catch(Exception e) {
platformTransactionManager.rollback(status);
}
实际项目运用
上面展示了实现Spring编程式事务的一些基本步骤,接下来展示如何应用在青芒项目中多线程事务处理
- 定义 TransactionStatus的同步集合
注意上图的 List
启动线程
使用statusList将当前的事务状态放进同步集合里,每当业务处理中有出错信息,则回滚每个线程中的事务,同时抛出异常。
注意:在子线程里的异常是不能被主线程捕获,如果子线程发生异常,而内部不处理,则会逃逸到控制台,所以子线程的异常要在子线程自己内部处理。这时要想将异常被主线程捕获,可以使用比较多的方法,如UncaughtExceptionHandler,Futrue等等,这里使用线程框架 Executors + Future去将子线程发生的异常捕获出来。
总结
在多线程中保证事务,在Spring里可以利用同步集合 + 编程式事务实现,同时要想获取子线程的事务,可以使用线程框架Executors的submit + Futrue获取结果,遍历结果,可以获得错误信息。