不使用事務,如果當前事務存在,則丟擲異常
驗證:
@Service public class PrService { @Autowired PrDao dao; @Transactional public void savea() { dao.a();//儲存第一條資料 saveb(); } @Transactional(propagation = Propagation.NEVER) private void saveb() { dao.b();//儲存第二條資料 int i=1/0; } }
寫一個controller呼叫這個savea方法,頁面看到的是/ by zero,資料庫中兩條資料都沒有插入進去,都回滾了。照說設定了Propagation.NEVER,應該saveb方法根本執行不了,報never的錯。為什麼執行了呢?
因為是直接呼叫的saveb(),不是從代理物件上呼叫的方法,改成這樣:
@Service public class PrService { @Autowired PrDao dao; @Autowired PrService prService; @Transactional public void savea() { dao.a();//儲存第一條資料 prService.saveb(); } @Transactional(propagation = Propagation.NEVER) private void saveb() { dao.b();//儲存第二條資料 int i=1/0; } }
注意這裡是 prService.saveb()和前面不同,但是居然在 dao.b(); 這一行報了一個空指標的錯誤,這就詭異了,這個dao明明在上面的savea方法裡面還有值的,你知道是為什麼嗎?
原來saveb方法的修飾符是private,導致代理物件無法繼承這個方法。改成public
public void saveb()
再次測試,看到期待的報錯了:
Existing transaction found for transaction marked with propagation 'never'
當前存在事務,則加入當前事務,如果當前事務不存在,則丟擲異常。
這裡把MANDATORY放在saveb方法上,就要把savea方法上的transactional註解去掉,才能看到報錯。
@Service public class PrService { @Autowired PrDao dao; @Autowired PrService prService; public void savea() { dao.a();//儲存第一條資料 prService.saveb(); } @Transactional(propagation = Propagation.MANDATORY) public void saveb() { dao.b();//儲存第二條資料 } }
或者直接把MANDATORY放在a方法上也會報錯:
@Service public class PrService { @Transactional(propagation = Propagation.MANDATORY) public void savea() { } }
報錯如下
No existing transaction found for transaction marked with propagation 'mandatory'
REQUIRES_NEW
建立一個新事務,如果存在當前事務,則掛起該事務。
可以理解為設定事務傳播型別為REQUIRES_NEW的方法,在執行時,不論當前是否存在事務,總是會新建一個事務。
現在寫一個demo驗證,savea方法呼叫saveb方法,希望saveb方法裡面異常了且事務回滾,savea方法裡面不回滾
下面驗證:
同樣為了在避免事務失效,在代理物件上呼叫方法,將被呼叫的方法放到一個單獨的類中:
@Service public class PrService { @Autowired PrDao dao; @Autowired SaveBService saveBService; @Transactional public void savea() { dao.a();//插入第一條資料 saveBService.saveb(); } }
@Service public class SaveBService { @Autowired PrDao dao; @Transactional(propagation = Propagation.REQUIRES_NEW) public void saveb() { dao.b();//插入第二條資料 int i = 1/0; } }
這裡PrService的savea方法呼叫SaveBService的saveb方法,寫一個controller存取savea方法,頁面看到一個異常 / by zero,再檢查資料庫,兩條資料都有沒有插入進去。這是為什麼呢?看上去第二個方法已經寫到獨立的類中了。
原來是因為saveb方法丟擲的異常savea方法沒有捕獲,又丟擲去了,當然要回滾了。寫個try catch就行:
@Transactional public void savea() { dao.a();//插入第一條資料 try { saveBService.saveb(); }catch (Exception e) { System.out.println("some error"); } }
再次測試,第二條資料沒有插入,第一條資料插入到資料庫了,頁面也看不到報錯了。