spring 多线程事务的问题

时间:2021-01-30 23:19:10

因为线程不属于spring托管,故线程不能够默认使用spring的事务,也不能获取spring注入的bean在被spring声明式事务管理的方法内开启多线程,多线程内的方法不被事务控制。

如下代码,线程内调用insert方法,spring不会把insert方法加入事务,就算在insert方法上加入@Transactional注解,也不起作用。
因为调用本类的方法,会让注解,还是AOP切面无法注切入(具体看事务管理实现源码)。调用别的类的话,然后就会有事务切入,然后就会有管理。

Java代码  spring 多线程事务的问题
  1. @Service  
  2. public class ServiceA {  
  3.    
  4.     @Transactional  
  5.     public void threadMethod(){  
  6.         this.insert();  
  7.          System.out.println("main insert is over");  
  8.         for(int a=0 ;a<3;a++){  
  9.             ThreadOperation threadOperation= new ThreadOperation();  
  10.             Thread innerThread = new Thread(threadOperation);  
  11.             innerThread.start();  
  12.         }  
  13.     }  
  14.    
  15.     public  class ThreadOperation implements Runnable {  
  16.         public ThreadOperation(){  
  17.         }  
  18.         @Override  
  19.         public void run(){  
  20.             insert();  
  21.             System.out.println("thread insert is over");  
  22.         }  
  23.     }  
  24.    
  25.     public void insert(){  
  26.    
  27.     //do insert......  
  28.    
  29.     }  
  30. }  

 

 

如果吧上面insert方法提出到新的类中,加入事务注解,就能成功的把insert方法加入到事务管理当中

Java代码  spring 多线程事务的问题
  1. @Service  
  2. public class ServiceA {  
  3.    
  4. @Autowired  
  5. private ServiceB serviceB;  
  6.    
  7.     @Transactional  
  8.     public void threadMethod(){  
  9.         this.insert();  
  10.         System.out.println("main insert is over");  
  11.         for(int a=0 ;a<3;a++){  
  12.             ThreadOperation threadOperation= new ThreadOperation();  
  13.             Thread innerThread = new Thread(threadOperation);  
  14.             innerThread.start();  
  15.         }  
  16.     }  
  17.    
  18.     public  class ThreadOperation implements Runnable {  
  19.         public ThreadOperation(){  
  20.         }  
  21.         @Override  
  22.         public void run(){  
  23.             serviceB.insert();  
  24.             System.out.println("thread insert is over");  
  25.         }  
  26.     }  
  27.    
  28.     public void insert(){  
  29.    
  30.         //do insert......  
  31.    
  32.     }  
  33. }  
  34.    
  35. @Service  
  36. public class ServiceB {  
  37.    
  38.     @Transactional  
  39.     public void insert(){  
  40.    
  41.         //do insert......  
  42.    
  43.     }  
  44.    
  45. }  

 

 

 

另外,使用多线程事务的情况下,进行回滚,比较麻烦。

thread的run方法,有个特别之处,它不会抛出异常,但异常会导致线程终止运行。

最麻烦的是,在线程中抛出的异常即使在主线程中使用try...catch也无法截获

这非常糟糕,我们必须要“感知”到异常的发生。比如某个线程在处理重要的事务,当thread异常终止,我必须要收到异常的报告,才能回滚事务。

这时可以使用线程的UncaughtExceptionHandler进行异常处理,UncaughtExceptionHandler名字意味着处理未捕获的异常。更明确的说,它处理未捕获的运行时异常

 

如下代码

线程出要使用

①处要抛出异常

②处要捕捉异常,并且要抛出RuntimeException

③处手动处理回滚逻辑

Java代码  spring 多线程事务的问题
  1. @Service  
  2. public class ServiceA {  
  3.    
  4. @Autowired  
  5. private ServiceB serviceB;  
  6.    
  7.     @Transactional  
  8.     public void threadMethod(){  
  9.         this.insert();  
  10.         System.out.println("main insert is over");  
  11.         for(int a=0 ;a<3;a++){  
  12.             ThreadOperation threadOperation= new ThreadOperation();  
  13.             Thread innerThread = new Thread(threadOperation);  
  14.             innerThread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {  
  15.                public void uncaughtException(Thread t, Throwable e) {  
  16.                    try {  
  17.                         serviceB.delete();③  
  18.                    } catch (Exception e1) {  
  19.                        e1.printStackTrace();  
  20.                    }  
  21.                }  
  22.             });  
  23.             innerThread.start();  
  24.         }  
  25.     }  
  26.    
  27.     public  class ThreadOperation implements Runnable {  
  28.         public ThreadOperation(){  
  29.         }  
  30.         @Override  
  31.         public void run(){  
  32.             try {  
  33.                serviceB.insert();  
  34.            }catch (Exception ex){ ②  
  35.             System.out.println(" Exception in run ");  
  36.                throw new RuntimeException();  
  37.            }  
  38.             System.out.println("thread insert is over");  
  39.         }  
  40.     }  
  41.    
  42.     public void insert(){  
  43.    
  44.         //do insert......  
  45.    
  46.     }  
  47. }  
  48.    
  49. @Service  
  50. public class ServiceB {  
  51.    
  52.     @Transactional  
  53.     public void insert() throws Exception{ ①  
  54.    
  55.     //do insert......  
  56.    
  57.     }  
  58.    
  59.     @Transactional  
  60.     public void delete() throws Exception{   
  61.    
  62.         //do delete......  
  63.    
  64.     }  
  65.    
  66. }