javascript
面试官:Spring事务的传播行为有几种?
??點擊上方?好好學java?,選擇?星標?公眾號
重磅資訊、干貨,第一時間送達 今日推薦:程序員入職國企,1周上班5小時,曬出薪資感嘆:騰訊當CEO也不去個人原創+1博客:點擊前往,查看更多在Spring中使用事務
Spring事務支持兩種方式,編程式事務和聲明式事務,下面的例子使用聲明式事務,即@Transactional注解的方式
@Transactional注解應用到public方法,才能進行事務管理
| value(和transactionManager互為別名) | String | 當在配置文件中有多個PlatformTransactionManager ,用該屬性指定選擇哪個事務管理器 | 空字符串"" |
| propagation | 枚舉:Propagation | 事務的傳播行為 | REQUIRED |
| isolation | 枚舉:Isolation | 事務的隔離度 | DEFAULT |
| timeout | int | 事務的超時時間。如果超過該時間限制但事務還沒有完成,則自動回滾事務 | -1 |
| readOnly | boolean | 指定事務是否為只讀事務 | false |
| rollbackFor | Class[] | 需要回滾的異常 | 空數組{} |
| rollbackForClassName | String[] | 需要回滾的異常類名 | 空數組{} |
| noRollbackFor | Class[] | 不需要回滾的異常 | 空數組{} |
| noRollbackForClassName | String[] | 不需要回滾的異常類名 | 空數組{} |
@Transactional的其他屬性都比較容易理解,詳細分析一下事務的傳播行為
附上我歷時三個月總結的?Java 面試 + Java 后端技術學習指南,這是本人這幾年及春招的總結,目前,已經拿到了大廠offer,拿去不謝!
下載方式
1.?首先掃描下方二維碼
2.?后臺回復「Java面試」即可獲取
Spring事務的傳播行為
Spring事務的傳播行為在Propagation枚舉類中定義了如下幾種選擇
支持當前事務
REQUIRED :如果當前存在事務,則加入該事務。如果當前沒有事務,則創建一個新的事務
SUPPORTS:如果當前存在事務,則加入該事務 。如果當前沒有事務, 則以非事務的方式繼續運行
MANDATORY ?:如果當前存在事務,則加入該事務 。如果當前沒有事務,則拋出異常
不支持當前事務
REQUIRES_NEW :創建一個新事務,如果當前存在事務,則把當前事務掛起
NOT_SUPPORTED :以非事務方式運行,如果當前存在事務,則把當前事務掛起
NEVER :以非事務方式運行,如果當前存在事務,則拋出異常
其他情況
NESTED :如果當前存在事務,則創建一個事務作為當前事務的嵌套事務來執行 。如果當前沒有事務,則該取值等價于REQUIRED
以NESTED啟動的事務內嵌于外部事務中 (如果存在外部事務的話),此時內嵌事務并不是一個獨立的事務,它依賴于外部事務。只有通過外部事務的提交,才能引起內部事務的提交,嵌套的子事務不能單獨提交
代碼演示
建立如下2張表
CREATE?TABLE?`user`?(`id`?int(11)?NOT?NULL?AUTO_INCREMENT,`name`?varchar(20)?DEFAULT?NULL,PRIMARY?KEY?(`id`) )?ENGINE=InnoDB?DEFAULT?CHARSET=utf8; CREATE?TABLE?`location`?(`id`?int(11)?NOT?NULL?AUTO_INCREMENT,`name`?varchar(20)?DEFAULT?NULL,PRIMARY?KEY?(`id`) )?ENGINE=InnoDB?DEFAULT?CHARSET=utf8;public?interface?LocationService?{void?addLocation(String?location); }
@Component public?class?LocationServiceImpl?implements?LocationService?{@Autowiredprivate?JdbcTemplate?jdbcTemplate;@Override@Transactional(propagation?=?Propagation.REQUIRED)public?void?addLocation(String?location)?{String?sql?=?"insert?into?location?(`name`)?values?(?)";jdbcTemplate.update(sql,?new?Object[]{location});throw?new?RuntimeException("保存地址異常");} }
public?interface?UserService?{void?addUser(String?name,?String?location); }
@Component public?class?UserServiceImpl?implements?UserService?{@Autowiredprivate?JdbcTemplate?jdbcTemplate;@Autowiredprivate?LocationService?locationService;@Overridepublic?void?addUser(String?name,?String?location)?{String?sql?=?"insert?into?user?(`name`)?values?(?)";jdbcTemplate.update(sql,?new?Object[]{name});locationService.addLocation(location);} }
接下來我們就通過演示在addLocation和addUser方法上加不同屬性的@Transactional注解來演示spring事務的傳播行為
REQUIRED
如果當前存在事務,則加入該事務。如果當前沒有事務,則創建一個新的事務
當前沒有事務
//?沒有注解 addUser(String?name,?String?location)@Transactional(propagation?=?Propagation.REQUIRED) addLocation(String?location)結果:user正常插入,location沒有插入
當前有事務
@Transactional(propagation?=?Propagation.REQUIRED) addUser(String?name,?String?location)@Transactional(propagation?=?Propagation.REQUIRED) addLocation(String?location)結果:
addUser在調用addLocation時加了try catch,user和location表都沒有插入
addUser在調用addLocation時沒加try catch,user和location表都沒有插入
結論:因為雖然在2個方法上加了事務注解看起來像2個事務,可是在底層數據庫看來是一個事務,只要有一個回滾,則都會回滾
SUPPORTS
如果當前存在事務,則加入該事務 。如果當前沒有事務, 則以非事務的方式繼續運行
當前沒有事務
//?沒有注解 addUser(String?name,?String?location)@Transactional(propagation?=?Propagation.SUPPORTS) addLocation(String?location)結果:雖然addLocation拋出異常,但是user和location都正常插入
當前有事務
@Transactional(propagation?=?Propagation.REQUIRED) addUser(String?name,?String?location)@Transactional(propagation?=?Propagation.SUPPORTS) addLocation(String?location)結果:user和location都沒有插入
MANDATORY
如果當前存在事務,則加入該事務 。如果當前沒有事務,則拋出異常
當前沒有事務
//?沒有注解 addUser(String?name,?String?location)@Transactional(propagation?=?Propagation.MANDATORY) addLocation(String?location)結果:addLocation拋出IllegalTransactionStateException異常,user正常插入
當前有事務
@Transactional(propagation?=?Propagation.REQUIRED) addUser(String?name,?String?location)@Transactional(propagation?=?Propagation.MANDATORY) addLocation(String?location)結果:user和location都沒有插入
REQUIRES_NEW
創建一個新事務,如果當前存在事務,則把當前事務掛起
當前沒有事務
//?沒有注解 addUser(String?name,?String?location)@Transactional(propagation?=?Propagation.REQUIRES_NEW) addLocation(String?location)結果:user正常插入,location沒有插入
當前有事務
@Transactional(propagation?=?Propagation.REQUIRED) addUser(String?name,?String?location)@Transactional(propagation?=?Propagation.REQUIRES_NEW) addLocation(String?location)結果:
addUser調用addLocation時加了try catch,則user正常插入,location沒有插入
addUser調用addLocation時沒加try catch,user和location都沒有插入
結論:REQUIRES_NEW是創建新的事務運行,因此addUser和addLocation是2個獨立的事務
NOT_SUPPORTED
以非事務方式運行,如果當前存在事務,則把當前事務掛起
當前沒有事務
//?沒有注解 addUser(String?name,?String?location)@Transactional(propagation?=?Propagation.NOT_SUPPORTED) addLocation(String?location)結果:user和location都正常插入
當前有事務
@Transactional(propagation?=?Propagation.REQUIRED) addUser(String?name,?String?location)@Transactional(propagation?=?Propagation.NOT_SUPPORTED) addLocation(String?location)結果:
addUser調用addLocation時沒加try catch,location正常插入,user沒有插入
addUser調用addLocation時加了try catch,user和location都正常插入
NEVER
以非事務方式運行,如果當前存在事務,則拋出異常
當前沒有事務
//?沒有注解 addUser(String?name,?String?location)@Transactional(propagation?=?Propagation.NEVER) addLocation(String?location)結果:user和location都正常插入
當前有事務
@Transactional(propagation?=?Propagation.REQUIRED) addUser(String?name,?String?location)@Transactional(propagation?=?Propagation.NEVER) addLocation(String?location)結果:
addUser調用addLocation時沒加try catch,addLocation拋出IllegalTransactionStateException,user和location都沒有插入
addUser調用addLocation時加了try catch,addLocation拋出IllegalTransactionStateException,user正常插入,location沒有插入
NESTED
如果當前存在事務,則創建一個事務作為當前事務的嵌套事務來執行 。如果當前沒有事務,則該取值等價于REQUIRED
當前沒有事務
//?沒有注解 addUser(String?name,?String?location)@Transactional(propagation?=?Propagation.NESTED) addLocation(String?location)結果:user正常插入,location沒有插入
當前有事務
@Transactional(propagation?=?Propagation.REQUIRED) addUser(String?name,?String?location)@Transactional(propagation?=?Propagation.NESTED) addLocation(String?location)結果:
addUser調用addLocation時加了try catch,user成功插入,location沒有插入
addUser調用addLocation時沒加try catch,user和location都沒有成功插入
我們把上面的代碼改成如下,保存用戶時發生異常。保存地址時不會發生異常
@Component public?class?LocationServiceImpl?implements?LocationService?{@Autowiredprivate?JdbcTemplate?jdbcTemplate;@Override@Transactional(propagation?=?Propagation.NESTED)public?void?addLocation(String?location)?{String?sql?=?"insert?into?location?(`name`)?values?(?)";jdbcTemplate.update(sql,?new?Object[]{location});} }@Component public?class?UserServiceImpl?implements?UserService?{@Autowiredprivate?JdbcTemplate?jdbcTemplate;@Autowiredprivate?LocationService?locationService;@Override@Transactional(propagation?=?Propagation.REQUIRED)public?void?addUser(String?name,?String?location)?{String?sql?=?"insert?into?user?(`name`)?values?(?)";jdbcTemplate.update(sql,?new?Object[]{name});locationService.addLocation(location);throw?new?RuntimeException("保存用戶異常");} }
結果:user和location都沒有插入
結論:嵌套事務, ?它是已經存在事務的子事務, 嵌套事務開始執行時, ?它將取得一個savepoint。如果這個嵌套事務失敗, 將回滾到此savepoint。嵌套事務是外部事務的一部分, 只有外部事務正常提交它才會被提交。使用NESTED 有限制,它只支持 JDBC,且數據庫要支持 savepoint 保存點,還要 JDBC 的驅動在3.0以上、
最后,再附上我歷時三個月總結的?Java 面試 + Java 后端技術學習指南,這是本人這幾年及春招的總結,目前,已經拿到了大廠offer,拿去不謝!
下載方式
1.?首先掃描下方二維碼
2.?后臺回復「Java面試」即可獲取
總結
以上是生活随笔為你收集整理的面试官:Spring事务的传播行为有几种?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一个基于 Spring Boot 的项目
- 下一篇: 30 分钟学会如何使用 Shiro