這裏面有幾點須要你們留意:
A. 一個功能是否要事務,必須歸入設計、編碼考慮。不能僅僅完成了基本功能就ok。
B. 若是加了事務,必須作好開發環境測試(測試環境也儘可能觸發異常、測試回滾),確保事務生效。
C. 如下列了事務使用過程的注意事項,請你們留意。
1. 不要在接口上聲明@Transactional ,而要在具體類的方法上使用 @Transactional 註解,不然註解可能無效。
2.不要圖省事,將@Transactional放置在類級的聲明中,放在類聲明,會使得全部方法都有事務。故@Transactional應該放在方法級別,不須要使用事務的方法,就不要放置事務,好比查詢方法。不然對性能是有影響的。
3.使用了@Transactional的方法,對同一個類裏面的方法調用, @Transactional無效。好比有一個類Test,它的一個方法A,A再調用Test本類的方法B(無論B是否public仍是private),但A沒有聲明註解事務,而B有。則外部調用A以後,B的事務是不會起做用的。(常常在這裏出錯)
4.使用了@Transactional的方法,只能是public,@Transactional註解的方法都是被外部其餘類調用纔有效,故只能是public。道理和上面的有關聯。故在 protected、private 或者 package-visible 的方法上使用 @Transactional 註解,它也不會報錯,但事務無效。
5.通過在ICORE-CLAIM中測試,效果以下:
A.拋出受查異常XXXException,事務會回滾。
B.拋出運行時異常NullPointerException,事務會回滾。
C.Quartz中,execute直接調用加了@Transactional方法,能夠回滾;間接調用,不會回滾。(即上文3點提到的)
D.異步任務中,execute直接調用加了@Transactional方法,能夠回滾;間接調用,不會回滾。(即上文3點提到的)
E.在action中加上@Transactional,不會回滾。切記不要在action中加上事務。
F.在service中加上@Transactional,若是是action直接調該方法,會回滾,若是是間接調,不會回滾。(即上文3提到的)
G.在service中的private加上@Transactional,事務不會回滾。java
在同一個類中,一個方法調用另一個有註解(好比@Async,@Transational)的方法,註解是不會生效的。
好比,下面代碼例子中,有兩方法,一個有@Transational註解,一個沒有。若是調用了有註解的addPerson()方法,會啓動一個Transaction;若是調用updatePersonByPhoneNo(),由於它內部調用了有註解的addPerson(),若是你覺得系統也會爲它啓動一個Transaction,那就錯了,其實是沒有的。
- @Service
- public class PersonServiceImpl implements PersonService {
-
- @Autowired
- PersonDao personDao;
-
- @Override
- @Transactional
- public boolean addPerson(Person person) {
- boolean result = personDao.insertPerson(person)>0 ? true : false;
- return result;
- }
-
- @Override
-
- public boolean updatePersonByPhoneNo(Person person) {
- boolean result = personDao.updatePersonByPhoneNo(person)>0 ? true : false;
- addPerson(person);
- return result;
- }
- }
如何查看是否啓動了Transaction?
設置log leve爲debug,能夠查看是否有下面這個log,判斷是否啓動了Transaction:
DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager - Creating new transaction with name...
一樣地,@Async等其餘註解也有這樣的問題。
緣由:
spring 在掃描bean的時候會掃描方法上是否包含@Transactional註解,若是包含,spring會爲這個bean動態地生成一個子類(即代理類,proxy),代理類是繼承原來那個bean的。此時,當這個有註解的方法被調用的時候,其實是由代理類來調用的,代理類在調用以前就會啓動transaction。然而,若是這個有註解的方法是被同一個類中的其餘方法調用的,那麼該方法的調用並無經過代理類,而是直接經過原來的那個bean,因此就不會啓動transaction,咱們看到的現象就是@Transactional註解無效。
爲何一個方法a()調用同一個類中另一個方法b()的時候,b()不是經過代理類來調用的呢?能夠看下面的例子(爲了簡化,用僞代碼表示):
- @Service
- class A{
- @Transactinal
- method b(){...}
-
- method a(){
- b();
- }
- }
-
- class proxy$A{
- A objectA = new A();
- method b(){
- startTransaction();
- objectA.b();
- }
-
- method a(){
- objectA.a();
- }
- }
當咱們調用A的bean的a()方法的時候,也是被proxy$A攔截,執行proxy$A.a()(標記3),然而,由以上代碼可知,這時候它調用的是objectA.a(),也就是由原來的bean來調用a()方法了,因此代碼跑到了「標記1」。因而可知,「標記2」並無被執行到,因此startTransaction()方法也沒有運行。
瞭解了失效的緣由,解決的方法就簡單了(兩種):
- 把這兩個方法分開到不一樣的類中;
- 把註解加到類名上面;