1. 程式人生 > 其它 >添加了@@Transactional註解後,事務不生效

添加了@@Transactional註解後,事務不生效

故事梗概

事情是這樣的,在使用Jpa的saveAll方法的時候,發現saveAll方法會進行先查詢後儲存的操作,但我只想要儲存,不想要查詢
關於saveAll的重寫 可以這樣用


    @PersistenceContext
    private EntityManager em;

    @Override
    public <T> void saveAll(Iterable<T> entities) {
        for (T entity : entities) {
            em.persist(entity);
        }
        em.flush();
        em.clear();
    }

完成了重寫之後,發現數據存不進去,而且報錯了:No EntityManager with actual transaction available for current thread
這個報錯的原因是沒有加事務,其實我在saveAll方法上加了@Transactional註解的,但是並沒有生效

一般的@Transactional不生效的原因

1、檢查你的方法是不是public的,@Transactional註解只能應用到public可見度的方法上,如果應用在protected、private或者package可見度的方法上,也不會報錯,不過事務設定不會起作用。
2、檢查你的異常型別是不是unchecked異常。預設情況下,Spring會對unchecked異常進行事務回滾,如果是checked異常則不回滾。如空指標異常、算術異常等,會被回滾;檔案讀寫、網路出問題,spring就沒法回滾了。如果你想check異常也回滾怎麼辦,註解上面寫明異常型別即可:
like this
@Transactional(rollbackFor = Exception.class)


3、是否在service中進行了try...catch的操作,由於已經被捕獲異常,故事務也不會回滾。如果非要在service中try...catch異常,又想要事務回滾,可在catch塊中丟擲執行時異常

try{
    ....  
}catch(Exception e){
    logger.error("",e);
    throw new RuntimeException;
}

這種方法有個不足之處,就是不能在catch塊中存在return子句,若想捕獲異常時回滾事務,同時返回提示資訊,可以使用手動回滾:


try{
    ...
}catch(Exception e){
    logger.error("",e);
    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
    return ERROR_MESSAGE;
}

PS:另外說明一下,在controller層捕獲了service層的異常,事務還會回滾嗎?答案是會的,只要你service層丟擲了異常,並且你加的事務可以處理這個異常,也就是rollbackFor = Exception.class這個符合你丟擲的異常,不管外面有沒有捕獲都可以回滾。
4、是否開啟了對註解的解析:

<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
          id="transactionManager">
        <property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>

5、資料庫引擎要支援事務,如果是mysql,注意表要使用支援事務的引擎,比如innodb,如果是myisam,事務是不起作用的。

6、spring是否掃描到你這個包,如下是掃描到org.test下面的包:
<context:component-scan base-package="org.test" ></context:component-scan>

解決

對我來說,以上都沒用,哈哈
真實的原因是,@Transactional沒加對地方,我把它加在了saveAll的方法上,但實際上我在save()方法中呼叫了一個create()方法,create()方法中才呼叫了saveAll()方法
諸位,看清這個關係 save()->create()->saveAll()
那麼@Transactional應該加在主方法save()上,而不是下面被呼叫的方法中

原因是事務可傳遞,Spring 的事務傳播策略在內部方法呼叫時將不起作用,事務註解加到要呼叫方法上

ps:注意@Transactional也不要加在介面上,因為spring 採用 aop 針對具體實現類做的代理實現

跳坑完畢,祝你快樂!!