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