Spring @Async/@Transactional 失效的原因及解決方案


在同一個類中,一個方法調用另外一個有注解(比如@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等其他注解也有這樣的問題。

原因:
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()方法也沒有運行。

了解了失效的原因,解決的方法就簡單了(兩種):
把這兩個方法分開到不同的類中;
把注解加到類名上面;

參考:https://blog.csdn.net/clementad/article/details/47339519


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM