天天看點

在同一個類中,一個方法調用另外一個有注解(比如@Async,@Transational)的方法,注解失效的原因和解決方法...

首先,感謝本文的作者,我覺得寫的比較透徹也很好了解。附上原文連結:

http://blog.csdn.net/clementad/article/details/47339519

正文:

在同一個類中,一個方法調用另外一個有注解(比如@Async,@Transational)的方法,注解是不會生效的。   比如,下面代碼例子中,有兩方法,一個有@Transational注解,一個沒有。如果調用了有注解的addPerson()方法,會啟動一個Transaction;如果調用upd

@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;  
 }  
}        

atePersonByPhoneNo(),因為它内部調用了有注解的addPerson(),如果你以為系統也會為它啟動一個Transaction,那就錯了,實際上是沒有的。 如何檢視是否啟動了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()方法也沒有運作。   了解了失效的原因,解決的方法就簡單了(兩種):

  1. 把這兩個方法分開到不同的類中;
  2. 把注解加到類名上面;

  參考: http://stackoverflow.com/questions/18590170/transactional-does-not-work-on-method-level   (原創文章,轉載請注明轉自:http://blog.csdn.net/clementad)

轉載于:https://www.cnblogs.com/sstone/p/7380121.html