首頁>技術>

本章內容概要@Transactional註解失效問題的描述和復現@Transactional註解失效原理講解@Transactional註解失效的解決方案問題描述

首先請大家看一下下面的程式碼,大家覺得有問題嗎?程式碼的期望是子事務遇到異常進行回滾,而父事務不受其影響,在外部呼叫addParent()後,大家覺這段程式碼能做到嗎?先賣個關子,請大家繼續往下看哦,不看的話,就可能錯過啥了哦。

什麼,上面的程式碼程式碼居然沒有起作用,咋回事?那接下來就給大家帶來原理分析,這個主要是Spring的事務是實現依賴AOP,其最底層其實是JDK動態代理或cglib動態代理,就是在代理的方法中呼叫代理的方法,被動的另一方法會不起作用。下面給大家用JDK動態代理來模擬一下現象

1.先宣告個介面

public interface TransactionalInterface { void createTransactional(); void commitTransactional();}

2.正常的實現類

public class TestTransactionalImpl implements TransactionalInterface{ @Override public void createTransactional() { System.out.println("===========createTransactional============"); commitTransactional(); } @Override public void commitTransactional() { System.out.println("===========commitTransactional============"); }}

3.代理的實現

public class ProxyTransactionalImpl implements InvocationHandler { private TransactionalInterface target; public ProxyTransactionalImpl(TransactionalInterface target) { this.target = target; } public TransactionalInterface createProxy(){ return (TransactionalInterface)Proxy.newProxyInstance(ProxyTransactionalImpl.class.getClassLoader(), new Class[] {TransactionalInterface.class}, this ); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if(method.getName().startsWith("c")){ System.out.println("==============Proxy================="); } return method.invoke(target,args); } public static void main(String[] args){ TestTransactionalImpl testTransactional = new TestTransactionalImpl(); ProxyTransactionalImpl proxyTransactional = new ProxyTransactionalImpl(testTransactional); TransactionalInterface proxy =proxyTransactional.createProxy(); proxy.createTransactional(); System.out.println("==============直接呼叫============="); proxy.commitTransactional(); }}

輸出的現象

從圖中可以看出代理類直接呼叫方法,代理是起作用的,如果在代理方法中呼叫代理方法,則是無效的

解決方案

注意資料庫的型別要是InnoDB,Spring預設回滾的異常是RuntimeException,如果需要回滾Exception異常可以設定@Transactional(rollbackFor=Exception.class)來解決問題

1.使用xxxService.xxx()方法的形式,也是把被呼叫的方法重新移到一個類裡

2.如果一定想在同一個類中呼叫的話,可以使用getBean方式來呼叫

try{ UserService userService = (UserService) applicationContext.getBean("userService"); userService.addOperatorRecord();}catch (Exception e){ log.error("子事務出錯了");}User user = new User();user.setName("parent");user.setAge(50);userMapper.insert(user);

4087

資料庫

最新評論
  • 1 #

    這好像和事物沒關係,是你切面用的姿勢不對

  • 2 #

    事務的傳播機制了解一下

  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 從0到1設計一個MQ訊息佇列