因为线程不属于spring托管,故线程不能够默认使用spring的事务,也不能获取spring注入的bean在被spring声明式事务管理的方法内开启多线程,多线程内的方法不被事务控制。
如下代码,线程内调用insert方法,spring不会把insert方法加入事务,就算在insert方法上加入@Transactional注解,也不起作用。
因为调用本类的方法,会让注解,还是AOP切面无法注切入(具体看事务管理实现源码)。调用别的类的话,然后就会有事务切入,然后就会有管理。
- @Service
- public class ServiceA {
- @Transactional
- public void threadMethod(){
- this.insert();
- System.out.println("main insert is over");
- for(int a=0 ;a<3;a++){
- ThreadOperation threadOperation= new ThreadOperation();
- Thread innerThread = new Thread(threadOperation);
- innerThread.start();
- }
- }
- public class ThreadOperation implements Runnable {
- public ThreadOperation(){
- }
- @Override
- public void run(){
- insert();
- System.out.println("thread insert is over");
- }
- }
- public void insert(){
- //do insert......
- }
- }
如果吧上面insert方法提出到新的类中,加入事务注解,就能成功的把insert方法加入到事务管理当中
- @Service
- public class ServiceA {
- @Autowired
- private ServiceB serviceB;
- @Transactional
- public void threadMethod(){
- this.insert();
- System.out.println("main insert is over");
- for(int a=0 ;a<3;a++){
- ThreadOperation threadOperation= new ThreadOperation();
- Thread innerThread = new Thread(threadOperation);
- innerThread.start();
- }
- }
- public class ThreadOperation implements Runnable {
- public ThreadOperation(){
- }
- @Override
- public void run(){
- serviceB.insert();
- System.out.println("thread insert is over");
- }
- }
- public void insert(){
- //do insert......
- }
- }
- @Service
- public class ServiceB {
- @Transactional
- public void insert(){
- //do insert......
- }
- }
另外,使用多线程事务的情况下,进行回滚,比较麻烦。
thread的run方法,有个特别之处,它不会抛出异常,但异常会导致线程终止运行。
最麻烦的是,在线程中抛出的异常即使在主线程中使用try...catch也无法截获
这非常糟糕,我们必须要“感知”到异常的发生。比如某个线程在处理重要的事务,当thread异常终止,我必须要收到异常的报告,才能回滚事务。
这时可以使用线程的UncaughtExceptionHandler进行异常处理,UncaughtExceptionHandler名字意味着处理未捕获的异常。更明确的说,它处理未捕获的运行时异常
如下代码
线程出要使用
①处要抛出异常
②处要捕捉异常,并且要抛出RuntimeException
③处手动处理回滚逻辑
- @Service
- public class ServiceA {
- @Autowired
- private ServiceB serviceB;
- @Transactional
- public void threadMethod(){
- this.insert();
- System.out.println("main insert is over");
- for(int a=0 ;a<3;a++){
- ThreadOperation threadOperation= new ThreadOperation();
- Thread innerThread = new Thread(threadOperation);
- innerThread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
- public void uncaughtException(Thread t, Throwable e) {
- try {
- serviceB.delete();③
- } catch (Exception e1) {
- e1.printStackTrace();
- }
- }
- });
- innerThread.start();
- }
- }
- public class ThreadOperation implements Runnable {
- public ThreadOperation(){
- }
- @Override
- public void run(){
- try {
- serviceB.insert();
- }catch (Exception ex){ ②
- System.out.println(" Exception in run ");
- throw new RuntimeException();
- }
- System.out.println("thread insert is over");
- }
- }
- public void insert(){
- //do insert......
- }
- }
- @Service
- public class ServiceB {
- @Transactional
- public void insert() throws Exception{ ①
- //do insert......
- }
- @Transactional
- public void delete() throws Exception{
- //do delete......
- }
- }