本章內容概要@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);
最新評論
-
1 #
-
2 #
事務的傳播機制了解一下
這好像和事物沒關係,是你切面用的姿勢不對