国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

Spring聲明式事務在哪些情況下會失效?

開發 架構
在Spring中事務管理的方式有兩種,編程式事務和聲明式事務。先詳細介紹一下兩種事務的實現方式

[[393241]]

編程式事務

在Spring中事務管理的方式有兩種,編程式事務和聲明式事務。先詳細介紹一下兩種事務的實現方式.

配置類

  1. @Configuration 
  2. @EnableTransactionManagement 
  3. @ComponentScan("com.javashitang"
  4. public class AppConfig { 
  5.  
  6.     @Bean 
  7.     public DruidDataSource dataSource() { 
  8.         DruidDataSource ds = new DruidDataSource(); 
  9.         ds.setDriverClassName("com.mysql.jdbc.Driver"); 
  10.         ds.setUrl("jdbc:mysql://localhost:3306/test?characterEncoding=utf8&useSSL=true"); 
  11.         ds.setUsername("test"); 
  12.         ds.setPassword("test"); 
  13.         ds.setInitialSize(5); 
  14.         return ds; 
  15.     } 
  16.  
  17.     @Bean 
  18.     public DataSourceTransactionManager dataSourceTransactionManager() { 
  19.         return new DataSourceTransactionManager(dataSource()); 
  20.     } 
  21.  
  22.     @Bean 
  23.     public JdbcTemplate jdbcTemplate(DataSource dataSource) { 
  24.         return new JdbcTemplate(dataSource); 
  25.     } 
  26.  
  27.     @Bean 
  28.     public TransactionTemplate transactionTemplate() { 
  29.         return new TransactionTemplate(dataSourceTransactionManager()); 
  30.     } 
  1. public interface UserService { 
  2.     void addUser(String name, String location); 
  3.     default void doAdd(String name) {}; 
  1. @Service 
  2. public class UserServiceV1Impl implements UserService { 
  3.  
  4.     @Autowired 
  5.     private JdbcTemplate jdbcTemplate; 
  6.     @Autowired 
  7.     private TransactionTemplate transactionTemplate; 
  8.  
  9.     @Override 
  10.     public void addUser(String name, String location) { 
  11.         transactionTemplate.execute(new TransactionCallbackWithoutResult() { 
  12.  
  13.             @Override 
  14.             protected void doInTransactionWithoutResult(TransactionStatus status) { 
  15.                 try { 
  16.                     String sql = "insert into user (`name`) values (?)"
  17.                     jdbcTemplate.update(sql, new Object[]{name}); 
  18.                     throw new RuntimeException("保存用戶信息失敗"); 
  19.                 } catch (Exception e) { 
  20.                     e.printStackTrace(); 
  21.                     status.setRollbackOnly(); 
  22.                 } 
  23.             } 
  24.         }); 
  25.     } 

可以看到編程式事務的方式并不優雅,因為業務代碼和事務代碼耦合到一塊,當發生異常的時候還得需要手動回滾事務(比使用JDBC方便多類,JDBC得先關閉自動自動提交,然后根據情況手動提交或者回滾事務)

如果讓你優化事務方法的執行?你會如何做?

「其實我們完全可以用AOP來優化這種代碼,設置好切點,當方法執行成功時提交事務,當方法發生異常時回滾事務,這就是聲明式事務的實現原理」

使用AOP后,當我們調用事務方法時,會調用到生成的代理對象,代理對象中加入了事務提交和回滾的邏輯。

聲明式事務

Spring aop動態代理的方式有如下幾種方法

JDK動態代理實現(基于接口)(JdkDynamicAopProxy)

CGLIB動態代理實現(動態生成子類的方式)(CglibAopProxy)

AspectJ適配實現

spring aop默認只會使用JDK和CGLIB來生成代理對象

@Transactional可以用在哪里?

@Transactional可以用在類,方法,接口上

用在類上,該類的所有public方法都具有事務

用在方法上,方法具有事務。當類和方法同時配置事務的時候,方法的屬性會覆蓋類的屬性

用在接口上,一般不建議這樣使用,因為只有基于接口的代理會生效,如果Spring AOP使用cglib來實現動態代理,會導致事務失效(因為注解不能被繼承)

@Transactional失效的場景

@Transactional注解應用到非public方法(除非特殊配置,例如使用AspectJ 靜態織入實現 AOP)

自調用,因為@Transactional是基于動態代理實現的

異常在代碼中被你自己try catch了

異常類型不正確,默認只支持RuntimeException和Error,不支持檢查異常

事務傳播配置不符合業務邏輯

@Transactional注解應用到非public方法

「為什么只有public方法上的@Transactional注解才會生效?」

首相JDK動態代理肯定只能是public,因為接口的權限修飾符只能是public。cglib代理的方式是可以代理protected方法的(private不行哈,子類訪問不了父類的private方法)如果支持protected,可能會造成當切換代理的實現方式時表現不同,增大出現bug的可能醒,所以統一一下。

「如果想讓非public方法也生效,你可以考慮使用AspectJ」

自調用,因為@Transactional是基于動態代理實現的

當自調用時,方法執行不會經過代理對象,所以會導致事務失效。例如通過如下方式調用addUser方法時,事務會失效

  1. // 事務失效 
  2. @Service 
  3. public class UserServiceV2Impl implements UserService { 
  4.  
  5.     @Autowired 
  6.     private JdbcTemplate jdbcTemplate; 
  7.  
  8.     @Override 
  9.     public void addUser(String name, String location) { 
  10.         doAdd(name); 
  11.     } 
  12.  
  13.     @Transactional 
  14.     public void doAdd(String name) { 
  15.         String sql = "insert into user (`name`) values (?)"
  16.         jdbcTemplate.update(sql, new Object[]{name}); 
  17.         throw new RuntimeException("保存用戶失敗"); 
  18.     } 

可以通過如下方式解決

  1. @Autowired注入自己,假如為self,然后通過self調用方法
  2. @Autowired ApplicationContext,從ApplicationContext通過getBean獲取自己,然后再調用
  1. // 事務生效 
  2. @Service 
  3. public class UserServiceV2Impl implements UserService { 
  4.  
  5.     @Autowired 
  6.     private JdbcTemplate jdbcTemplate; 
  7.     @Autowired 
  8.     private UserService userService; 
  9.  
  10.     @Override 
  11.     public void addUser(String name, String location) { 
  12.         userService.doAdd(name); 
  13.     } 
  14.  
  15.     @Override 
  16.     @Transactional 
  17.     public void doAdd(String name) { 
  18.         String sql = "insert into user (`name`) values (?)"
  19.         jdbcTemplate.update(sql, new Object[]{name}); 
  20.         throw new RuntimeException("保存用戶失敗"); 
  21.     } 

異常在代碼中被你自己try catch了

這個邏輯從源碼理解比較清晰,只有當執行事務拋出異常才能進入completeTransactionAfterThrowing方法,這個方法里面有回滾的邏輯,如果事務方法都沒拋出異常就只會正常提交

  1. // org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction 
  2.  
  3. try { 
  4.   // This is an around advice: Invoke the next interceptor in the chain. 
  5.   // This will normally result in a target object being invoked. 
  6.   // 執行事務方法 
  7.   retVal = invocation.proceedWithInvocation(); 
  8. catch (Throwable ex) { 
  9.   // target invocation exception 
  10.   completeTransactionAfterThrowing(txInfo, ex); 
  11.   throw ex; 
  12. finally { 
  13.   cleanupTransactionInfo(txInfo); 

異常類型不正確,默認只支持RuntimeException和Error,不支持檢查異常

異常體系圖如下。當拋出檢查異常時,spring事務不會回滾。如果拋出任何異常都回滾,可以配置rollbackFor為Exception

  1. @Transactional(rollbackFor = Exception.class) 

事務傳播配置不符合業務邏輯

假如說有這樣一個場景,用戶注冊,依次保存用戶基本信息到user表中,用戶住址信息到地址表中,當保存用戶住址信息失敗時,我們也要保證用戶信息注冊成功。

  1. public interface LocationService { 
  2.     void addLocation(String location); 
  1. @Service 
  2. public class LocationServiceImpl implements LocationService { 
  3.  
  4.     @Autowired 
  5.     private JdbcTemplate jdbcTemplate; 
  6.  
  7.     @Override 
  8.     @Transactional 
  9.     public void addLocation(String location) { 
  10.         String sql = "insert into location (`name`) values (?)"
  11.         jdbcTemplate.update(sql, new Object[]{location}); 
  12.         throw new RuntimeException("保存地址異常"); 
  13.     } 
  1. @Service 
  2. public class UserServiceV3Impl implements UserService { 
  3.  
  4.     @Autowired 
  5.     private JdbcTemplate jdbcTemplate; 
  6.     @Autowired 
  7.     private LocationService locationService; 
  8.  
  9.     @Override 
  10.     @Transactional 
  11.     public void addUser(String name, String location) { 
  12.         String sql = "insert into user (`name`) values (?)"
  13.         jdbcTemplate.update(sql, new Object[]{name}); 
  14.         locationService.addLocation(location); 
  15.     } 

調用發現user表和location表都沒有插入數據,并不符合我們期望,你可能會說拋出異常了,事務當然回滾了。好,我們把調用locationService的部分加上try catch

  1. @Service 
  2. public class UserServiceV3Impl implements UserService { 
  3.  
  4.     @Autowired 
  5.     private JdbcTemplate jdbcTemplate; 
  6.     @Autowired 
  7.     private LocationService locationService; 
  8.  
  9.     @Override 
  10.     @Transactional 
  11.     public void addUser(String name, String location) { 
  12.         String sql = "insert into user (`name`) values (?)"
  13.         jdbcTemplate.update(sql, new Object[]{name}); 
  14.         try { 
  15.             locationService.addLocation(location); 
  16.         } catch (Exception e) { 
  17.             e.printStackTrace(); 
  18.         } 
  19.     } 

調用發現user表和location表還是都沒有插入數據。這是因為在LocationServiceImpl中事務已經被標記成回滾了,所以最終事務還會回滾。

要想最終解決就不得不提到Spring的事務傳播行為了,不清楚的小伙伴看《面試官:Spring事務的傳播行為有幾種?》

Transactional的事務傳播行為默認為Propagation.REQUIRED?!溉绻斍按嬖谑聞?,則加入該事務。如果當前沒有事務,則創建一個新的事務」

此時我們把LocationServiceImpl中Transactional的事務傳播行為改成Propagation.REQUIRES_NEW即可

「創建一個新事務,如果當前存在事務,則把當前事務掛起」

所以最終的解決代碼如下

  1. @Service 
  2. public class UserServiceV3Impl implements UserService { 
  3.  
  4.     @Autowired 
  5.     private JdbcTemplate jdbcTemplate; 
  6.     @Autowired 
  7.     private LocationService locationService; 
  8.  
  9.     @Override 
  10.     @Transactional 
  11.     public void addUser(String name, String location) { 
  12.         String sql = "insert into user (`name`) values (?)"
  13.         jdbcTemplate.update(sql, new Object[]{name}); 
  14.         try { 
  15.             locationService.addLocation(location); 
  16.         } catch (Exception e) { 
  17.             e.printStackTrace(); 
  18.         } 
  19.     } 
  20. @Service 
  21. public class LocationServiceImpl implements LocationService { 
  22.  
  23.     @Autowired 
  24.     private JdbcTemplate jdbcTemplate; 
  25.  
  26.     @Override 
  27.     @Transactional(propagation = Propagation.REQUIRES_NEW) 
  28.     public void addLocation(String location) { 
  29.         String sql = "insert into location (`name`) values (?)"
  30.         jdbcTemplate.update(sql, new Object[]{location}); 
  31.         throw new RuntimeException("保存地址異常"); 
  32.     } 
  1. @Service 
  2. public class LocationServiceImpl implements LocationService { 
  3.  
  4.     @Autowired 
  5.     private JdbcTemplate jdbcTemplate; 
  6.  
  7.     @Override 
  8.     @Transactional(propagation = Propagation.REQUIRES_NEW) 
  9.     public void addLocation(String location) { 
  10.         String sql = "insert into location (`name`) values (?)"
  11.         jdbcTemplate.update(sql, new Object[]{location}); 
  12.         throw new RuntimeException("保存地址異常"); 
  13.     } 

 

責任編輯:武曉燕 來源: Java識堂
相關推薦

2024-11-29 11:01:25

2021-12-13 11:12:41

Spring事務失效

2009-06-22 09:01:57

Spring聲明式事務

2022-04-13 20:53:15

Spring事務管理

2024-11-13 19:03:14

2022-12-06 10:39:43

Spring事務失效

2021-09-06 13:42:14

Spring聲明式事務

2022-09-14 19:50:22

事務場景流程

2022-09-22 09:57:20

Spring事務失效

2024-08-01 08:29:45

Spring參數類型

2009-02-11 13:08:29

事務提交事務管理Spring

2009-02-11 11:14:31

事務管理事務開始Spring

2022-02-14 16:53:57

Spring項目數據庫

2023-05-26 07:19:49

Spring聲明式事務

2023-10-26 07:32:42

2009-06-22 11:01:12

2022-07-05 14:19:30

Spring接口CGLIB

2021-11-08 15:17:15

變量Defer 失效

2023-07-05 08:45:18

Spring事務失效場景

2025-01-16 08:45:48

點贊
收藏

51CTO技術棧公眾號

日韩av自拍| 欧美性高清videossexo| 精品国产乱码久久久久久108| 亚洲午夜剧场| 欧美日韩精品三区| 好吊妞这里只有精品| 国产91丝袜在线播放0| 欧洲成人一区二区| 久久久久久久久久久免费精品| 午夜毛片在线| 在线亚洲一区观看| 草草久视频在线观看电影资源| 99re这里只有精品首页| 黄色网络在线观看| 开心九九激情九九欧美日韩精美视频电影| 99精品在线直播| 日韩精品久久久久久久电影99爱| 亚洲18私人小影院| 日韩av三区| 人人澡人人澡人人看欧美| 97久久精品一区二区三区的观看方式| 亚洲第一黄色网| 牛牛在线精品视频| 欧美一级二级三级蜜桃| eeuss影院在线观看| 欧美亚洲一区二区在线观看| 可以在线观看的av| 欧美另类变人与禽xxxxx| 麻豆影院在线| 制服丝袜成人动漫| 免费网站在线观看人| 亚洲成在人线av| 浪潮色综合久久天堂| 中文字幕亚洲欧美| 91九色鹿精品国产综合久久香蕉| 欧美激情一级欧美精品| 欧美国产极品| 亚洲va欧美va在线观看| 在线成人国产| 中文字幕av日韩精品| 成人福利电影精品一区二区在线观看| 无码无遮挡又大又爽又黄的视频| 中日韩免费视频中文字幕| av日韩在线免费| 欧美日韩亚洲一区二区| 国产视频中文字幕在线观看| 亚洲国产日韩欧美在线动漫| 国产成人免费| 日本精品久久中文字幕佐佐木| 91精品久久久久久久久久不卡| 久久亚洲午夜电影| 成人国产精品视频| 黄色网免费看| 日韩一二三区不卡| 日韩黄色碟片| 国产精品久久久久久久久久尿| 国产欧美日韩影院| 奇米精品一区二区三区| 成人毛片视频在线观看| 老司机精品在线| 色先锋资源久久综合5566| 国产三级中文字幕| 972aa.com艺术欧美| http://嫩草影院| 欧美日韩在线综合| 成人免费网站www网站高清| 久久久久久久久久国产精品| 亚洲综合婷婷| 亚洲精品久久久久久久蜜桃臀| 国产精品乱码久久久久久| 亚洲热app| 亚洲人成人99网站| 欧美电影三区| 国产情侣第一页| 欧美日韩国产在线| abab456成人免费网址| 久久在线91| 天天插天天操天天射| 制服丝袜亚洲色图| 国产精品videossex| 欧美性bbwbbwbbwhd| 久久精品人人做人人爽97| 欧洲日本在线| 青草青草久热精品视频在线网站| 日韩高清国产一区在线| 美女视频免费观看网站在线| 亚洲老头同性xxxxx| 中文字幕日韩一区二区不卡 | 久久精品欧美视频| 欧美黄色一区二区| 国产a级一级片| 337p亚洲精品色噜噜狠狠| 欧美大奶一区二区| a级黄色片免费| 在线不卡中文字幕| 欧美日韩在线二区| 日本国产在线播放| 欧美成人高清电影在线| 99视频精品视频高清免费| 久久精品网站视频| 精品无码久久久久久国产| 午夜日韩视频| 日本午夜视频| 高清一区二区三区日本久| 不卡一二三区| 激情久久av| 一区二区三区在线视频观看| 成人不卡视频| 欧美xxxx吸乳| 91精品国产综合久久福利软件| 欧美艳星介绍134位艳星| 能在线观看的av网站| 日韩精品视频三区| 国产亚洲网站| 69久久精品| 国产精品日韩一区二区免费视频| 一区av在线播放| 亚洲精品无吗| 在线视频xx| 3344国产精品免费看| 久久久久久电影| 久久天堂久久| 色诱视频在线观看| 蜜臀久久99精品久久久无需会员 | 亚洲综合在线五月| 国产另类在线| 99热在线看| 78m国产成人精品视频| 91丝袜美腿高跟国产极品老师| 一根才成人网| 六月婷婷在线视频| 精品国产一区久久久| 91丨porny丨在线| 日本精品国产| 色琪琪原网站亚洲香蕉| 57pao成人永久免费视频| 亚洲人成网站精品片在线观看| 久本草在线中文字幕亚洲| 四虎国产精品成人免费4hu| 欧美一区视频在线| 午夜在线成人av| 亚洲成人精选| 成人黄色网址| 国产成人一二三区| 欧美成年人网站| 亚洲日本一区二区| 天天影视综合| 日本不卡影院| 日本福利视频一区| 孩xxxx性bbbb欧美| 精品久久香蕉国产线看观看gif| 午夜精品剧场| а√在线中文网新版地址在线| 亚洲小视频在线观看| 国产精品一区二区果冻传媒| av成人免费| 国产小黄视频| 国产91精品入口17c| 成人毛片在线观看| 成人在线日韩| 午夜免费啪视频观看视频| 99影视tv| 亚洲白虎美女被爆操| 国产经典欧美精品| 任你弄精品视频免费观看| 国产在线一二三区| 大荫蒂性生交片| 日本亚洲欧洲色α| 在线不卡中文字幕| 成人国产精品免费观看| 欧美美女视频| 女囚岛在线观看| 天堂在线资源视频| 国产高清不卡av| 国产亚洲视频在线观看| 亚洲特黄一级片| 免费在线成人| 日本在线视频一区二区三区| 最新中文字幕在线| 综合操久久久| 国产精品第一区| 亚洲成人免费在线视频| 国产视频一区不卡| 免费久久99精品国产自在现线| 日韩亚洲国产免费| 二区在线视频| 天天影视综合色| 好吊色欧美一区二区三区| 久久国产精品久久久久久久久久| 无码av免费一区二区三区试看 | 91麻豆swag| 久久人人88| 欧美日韩免费观看视频| 在线影院av| 久久免费视频3| 精品久久一区二区三区蜜桃| 久久91亚洲精品中文字幕| 3d动漫精品啪啪一区二区竹菊| 国产精品久久久久久亚洲伦| 日韩黄色小视频|