1. 程式人生 > >在同一個類中,一個方法呼叫另外一個有註解(比如@Async,@Transational)的方法,註解失效的原因和解決方法

在同一個類中,一個方法呼叫另外一個有註解(比如@Async,@Transational)的方法,註解失效的原因和解決方法

在同一個類中,一個方法呼叫另外一個有註解(比如@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
 //@Transactional
 public boolean updatePersonByPhoneNo(Person person) {
  boolean result = personDao.updatePersonByPhoneNo(person)>0 ? true : false;
  addPerson(person); //測試同一個類中@Transactional是否起作用
  return result;
 }
}

如何檢視是否啟動了Transaction?
設定log leve為debug,可以檢視是否有下面這個log,判斷是否啟動了Transaction:
DEBUG org.springframework.jdbc.datasource.DataSourceTransactionManager - Creating new transaction with name...

同樣地,@Async等其他註解也有這樣的問題。
(關於@Async的用法,請參考:http://blog.csdn.net/clementad/article/details/47403185)

原因:
spring 在掃描bean的時候會掃描方法上是否包含@Transactional註解,如果包含,spring會為這個bean動態地生成一個子類(即代理類,proxy),代理類是繼承原來那個bean的。此時,當這個有註解的方法被呼叫的時候,實際上是由代理類來呼叫的,代理類在呼叫之前就會啟動transaction。然而,如果這個有註解的方法是被同一個類中的其他方法呼叫的,那麼該方法的呼叫並沒有通過代理類,而是直接通過原來的那個bean,所以就不會啟動transaction,我們看到的現象就是@Transactional註解無效。

為什麼一個方法a()呼叫同一個類中另外一個方法b()的時候,b()不是通過代理類來呼叫的呢?可以看下面的例子(為了簡化,用偽程式碼表示):

@Service
class A{
    @Transactinal
    method b(){...}
    
    method a(){    //標記1
        b();
    }
}
 
//Spring掃描註解後,建立了另外一個代理類,併為有註解的方法插入一個startTransaction()方法:
class proxy$A{
    A objectA = new A();
    method b(){    //標記2
        startTransaction();
        objectA.b();
    }
 
    method a(){    //標記3
        objectA.a();    //由於a()沒有註解,所以不會啟動transaction,而是直接呼叫A的例項的a()方法
    }
}

當我們呼叫A的bean的a()方法的時候,也是被proxy$A攔截,執行proxy$A.a()(標記3),然而,由以上程式碼可知,這時候它呼叫的是objectA.a(),也就是由原來的bean來呼叫a()方法了,所以程式碼跑到了“標記1”。由此可見,“標記2”並沒有被執行到,所以startTransaction()方法也沒有執行。

瞭解了失效的原因,解決的方法就簡單了(兩種):
把這兩個方法分開到不同的類中;
把註解加到類名上面;
--------------------- 
作者:Clement-Xu 
來源:CSDN 
原文:https://blog.csdn.net/clementad/article/details/47339519 
版權宣告:本文為博主原創文章,轉載請附上博文連結!