1. 程式人生 > 實用技巧 >spring @transactional事務問題及解決

spring @transactional事務問題及解決

1. 資料庫引擎選擇錯誤

2.@transactional標註的方法 所在的類需要被spring管理 並且方法是public修飾

3. 自呼叫的時候出現的事務失效:

 1 @Service
 2 public class Service{
 3     
 4     public void m(){
 5         m1();
 6         m2();
 7 
 8     }
 9 
10     @transactional
11     public void m1(){
12 
13     
14     }
15     @transactional
16     public
void m2(){ 17 18 } 19 }
 1 @Service
 2 public class DmzService {
 3     @Transactional
 4     public void save(A a, B b) {
 5         saveB(b);
 6     }
 7     
 8     @Transactional(propagation = Propagation.REQUIRES_NEW)
 9     public void saveB(B b){
10         dao.saveB(b);
11     }
12
}

以上兩種情況皆會導致事務失敗,原因是 自呼叫呼叫的是目標類而不是代理類的方法,所以解決問題的點也在這裡

使用代理類的方法是

1. 自己autowire注入自己

2. 使用aopcontext

@Service
public class DmzService {

    @Transactional
    public void save(A a, B b) {
        ((DmzService) AopContext.currentProxy()).saveB(b);
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    
public void saveB(B b){ dao.saveB(b); } }

// exposeProxy=true代表將代理類放入到執行緒上下文中,預設是false
@EnableAspectJAutoProxy(exposeProxy = true)

事務回滾問題

  1. 想回滾卻提交了

  spring預設回滾是發生了error或者RunTimeException 如果想要回滾其他的異常 需要制定rollbackfor

  2. 想提交卻回滾了

  

@Service
public class DmzService {

    @Autowired
    IndexService indexService;

    @Transactional
    public void testRollbackOnly() {
        try {
            indexService.a();
        } catch (ClassNotFoundException e) {
            System.out.println("catch");
        }
    }
}

@Service
public class IndexService {
    @Transactional(rollbackFor = Exception.class)
    public void a() throws ClassNotFoundException{
        // ......
        throw new ClassNotFoundException();
    }
}

以上程式碼會丟擲異常! 原因是 事務巢狀的情況下,當內部事務回滾會把rollbackOnly屬性設定為true 所以會回滾

解決:

  1. 如果想內部事務回滾 外部事務繼續執行

    將內部事務的傳播級別設定為nested或者requires_new

    @Transactional(rollbackFor = Exception.class,propagation = Propagation.NESTED)

  2. 想內部事務發生異常 外部事務回滾 整體回滾 不拋異常

@Transactional
public void testRollbackOnly() {
try {
   indexService.a();
} catch (ClassNotFoundException e) {
   // 加上這句程式碼
   TransactionInterceptor.currentTransactionStatus().setRollbackOnly();
}
}