1. 程式人生 > >Spring在多執行緒的情況下,如何控制事務起作用

Spring在多執行緒的情況下,如何控制事務起作用

因為執行緒不屬於spring託管,故執行緒不能夠預設使用spring的事務,也不能獲取spring注入的bean在被spring宣告式事務管理的方法內開啟多執行緒,多執行緒內的方法不被事務控制。

如下程式碼,執行緒內呼叫insert方法,spring不會把insert方法加入事務就算在insert方法上加入@Transactional註解,也不起作用。

(?不解,試過將serviceA變成多例,也不行)

Java程式碼  收藏程式碼
  1. @Service  
  2. public class ServiceA {  
  3.     @Transactional  
  4.     public void threadMethod(){  
  5.         this
    .insert();  
  6.          System.out.println("main insert is over");  
  7.         for(int a=0 ;a<3;a++){  
  8.             ThreadOperation threadOperation= new ThreadOperation();  
  9.             Thread innerThread = new Thread(threadOperation);  
  10.             innerThread.start();  
  11.         }  
  12.     }  
  13.     public  class
     ThreadOperation implements Runnable {  
  14.         public ThreadOperation(){  
  15.         }  
  16.         @Override  
  17.         public void run(){  
  18.             insert();  
  19.             System.out.println("thread insert is over");  
  20.         }  
  21.     }  
  22.     public void insert(){  
  23.     //do insert......  
  24.     }  
  25. }  

如果吧上面insert方法提出到新的類中,加入事務註解,就能成功的把insert方法加入到事務管理當中

Java程式碼  收藏程式碼
  1. @Service  
  2. public class ServiceA {  
  3. @Autowired  
  4. private ServiceB serviceB;  
  5.     @Transactional  
  6.     public void threadMethod(){  
  7.         this.insert();  
  8.         System.out.println("main insert is over");  
  9.         for(int a=0 ;a<3;a++){  
  10.             ThreadOperation threadOperation= new ThreadOperation();  
  11.             Thread innerThread = new Thread(threadOperation);  
  12.             innerThread.start();  
  13.         }  
  14.     }  
  15.     public  class ThreadOperation implements Runnable {  
  16.         public ThreadOperation(){  
  17.         }  
  18.         @Override  
  19.         public void run(){  
  20.             serviceB.insert();  
  21.             System.out.println("thread insert is over");  
  22.         }  
  23.     }  
  24.     public void insert(){  
  25.         //do insert......  
  26.     }  
  27. }  
  28. @Service  
  29. public class ServiceB {  
  30.     @Transactional  
  31.     public void insert(){  
  32.         //do insert......  
  33.     }  
  34. }  

另外,使用多執行緒事務的情況下,進行回滾,比較麻煩。thread的run方法,有個特別之處,它不會丟擲異常,但異常會導致執行緒終止執行。

最麻煩的是,線上程中丟擲的異常即使在主執行緒中使用try...catch也無法截獲這非常糟糕,我們必須要“感知”到異常的發生。比如某個執行緒在處理重要的事務,當thread異常終止,我必須要收到異常的報告,才能回滾事務。這時可以使用執行緒的UncaughtExceptionHandler進行異常處理,UncaughtExceptionHandler名字意味著處理未捕獲的異常。更明確的說,它處理未捕獲的執行時異常。

如下程式碼

執行緒出要使用

①處要丟擲異常

②處要捕捉異常,並且要丟擲RuntimeException

③處手動處理回滾邏輯

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