一次與面試官:情景對話的一問一答,例數 Spring 事務的那些坑,你有遇到過嗎?
一次與面試官:情景對話的一問一答,例數 Spring 事務的那些坑,你有遇到過嗎?
今天,我們來講 Spring 中和事務有關的考題。
因為事務這塊,面試的出現機率很高。而大家工作中 CRUD 的比較多,沒有好好總結過這塊的知識,因此面試容易支支吾吾答不出來。於是乎接下來你就會接到一張好人卡,如"你很優秀,不適合我們公司!"
主要內容如下:
Spring 事務的原理;
Spring 什麼情況下進行事務回滾;
Spring 事務什麼時候失效;
Spring 事務和資料庫事務隔離是不是同一個概念;
Spring 事務控制放在 Service 層,在 Service 方法中一個方法呼叫 Service 中的另一個方法,預設開啟幾個事務;
怎麼保證 Spring 事務內的連線唯一性。
最新2020整理收集的一線網際網路公司面試真題(都整理成文件),有很多幹貨,包含netty,spring,執行緒,spring cloud等詳細講解,也有詳細的學習規劃圖,面試題整理等,我感覺在面試這塊講的非常清楚:獲取面試資料只需:點選這裡領取!!!暗號:CSDN
1. Spring 事務的原理
首先,我們先明白 Spring 事務的本質其實就是資料庫對事務的支援。沒有資料庫的事務支援,Spring 是無法提供事務功能的。
那麼,我們一般使用 JDBC 操作事務的程式碼如下:
獲取連線 Connection con = DriverManager.getConnection();
開啟事務 con.setAutoCommit(true/false);
執行 CRUD;
提交事務、回滾事務:con.commit() ,con.rollback();
關閉連線 conn.close()。
使用 Spring 事務管理後,我們可以省略步驟 2 和步驟 4,讓 AOP 幫你去做這些工作,關鍵類在 TransactionAspectSupport 這個切面裡。大家有興趣自己去翻,我就不列舉了。因為公眾號型別的文章,實在不適合寫一些原始碼解析!
2. Spring 什麼情況下進行事務回滾
首先我們要明白, Spring 事務回滾機制是這樣的:當所攔截的方法有指定異常丟擲,事務才會自動進行回滾!
因此,如果你默默的吞掉異常,像下面這樣:
@Service
public class UserService{
@Transactional
public void updateUser(User user) {
try {
System.out.println("孤獨煙真帥");
//do something
} catch {
//do something
}
}
}
那切面捕捉不到異常,肯定是不會回滾的。
還有就是,預設配置下,事務只會對 Error 與 RuntimeException 及其子類這些異常做出回滾。一般的 Exception 這些 Checked 異常不會發生回滾。如果一般的 Exception 想回滾,要做出如下配置:
@Transactional(rollbackFor = Exception.class)
但是在實際開發中,我們會遇到這麼一種情況:就是並沒有異常發生,但是由於事務結果未滿足具體業務需求,所以我們需要手動回滾事務。於是乎方法也很簡單:
自己在程式碼裡丟擲一個自定義異常(常用);
通過程式設計用程式碼回滾(不常用)。
TransactionAspectSupport.currentTransactionStatus()
.setRollbackOnly();
3. Spring 事務什麼時候失效
注意:這是一道經典題。4年前我畢業那會在問,我都工作4年了,現在還問這道。其出現頻率,不亞於 HashMap 的出現頻率!
該問題有很多問法,例如 Spring 事務有哪些坑?你用 Spring 事務的時候,有遇到過什麼問題麼?其實答案都一樣的。OK,不羅嗦了,開始答案!
我們知道 Spring 事務的原理是 AOP,進行了切面增強,那麼失效的根本原因是這個 AOP 不起作用了。
常見情況有以下幾種:
3.1 發生自呼叫
示例程式碼如下:
@Service
public class UserService{
public void update(User user) {
updateUser(user);
}
@Transactional
public void updateUser(User user) {
System.out.println("孤獨煙真帥");
//do something
}
}
此時是無效的。因此上面的程式碼等同於:
@Service
public class UserService{
public void update(User user) {
this.updateUser(user);
}
@Transactional
public void updateUser(User user) {
System.out.println("孤獨煙真帥");
//do something
}
}
此時,這個 this 物件不是代理類,而是 UserService 物件本身。
解決方法很簡單,讓那個 this 變成 UserService 的代理類即可,就不展開說明了。
3.2 方法修飾符不是 public
OK,我這裡不想舉原始碼。大家想一個邏輯就行:
@Transactional 註解的方法都是被外部其他類呼叫才有效,那麼如果方法修飾符是 private 的,這個方法能被外部其他類調到麼?
既然調不到,事務生效有意義嗎?想通這套邏輯就行了。
記住:@Transactional 註解只能應用到 public 方法上。如果你在 protected、private 或者 package-visible 的方法上使用 @Transactional 註解,它也不會報錯, 但是這個被註解的方法將不會加入事務之行。
先這麼理解就好了,因為真的去翻原因就要貼程式碼了,這文章可讀性就很差了。
3.3 發生了錯誤的異常
這個問題在第二問講過了,因為預設回滾的是:RuntimeException。如果是其他異常想要回滾,需要在 @Transactional 註解上加 rollbackFor 屬性。
又或者是異常被吞了,事務也會失效,這裡不再贅述。
3.4 資料庫不支援事務
畢竟 Spring 事務用的是資料庫的事務,如果資料庫不支援事務,那 Spring 事務肯定是無法生效滴。
OK,答到這裡就夠了。
可能有的讀者會說:
煙哥啊,其他文章裡說什麼資料來源沒有配置事務管理器也會導致事務失效,你怎麼沒提?
OK,我為什麼不提,因為這種情況屬於你配置的不對。隨便少一個配置都會導致事務不生效,例如我們在 Spring Boot 中的 Application 類上不加@EnableTransactionManagement 註解也會使事務不生效,難道您能將每種情況下的配置背下來?這種配置的東西,用到的時候臨時查詢即可。
再比如,你把隔離級別配置成:
@Transactional(propagation = Propagation.NOT_SUPPORTED)
該隔離級別表示不以事務執行,當前若存在事務則掛起,事務肯定不生效啊!這種屬於自己配錯的情況,如果真要舉例,面試官也不愛聽的!在面試中,一句"配置錯誤也會導致事務不生效,例如 xxx 配置,舉一兩個即可!"
4. Spring 事務隔離和資料庫事務隔離是不是一個概念
OK,是一回事!
我們先明確一點,資料庫一般有四種隔離級別,分別為:
Read Uncommitted:未提交讀;
Read Committed:提交讀、不可重複讀;
Repeatable Read:可重複讀;
Serializable:可序列化。
而 Spring 只是在此基礎上抽象出一種隔離級別 default,表示以資料庫預設配置的為主。例如,MySQL 預設的事務隔離級別為 Repeatable Read,而 Oracle 預設隔離級別為Read Committed。
於是乎,有一個經典問題是這麼問的:
我資料庫的配置隔離級別是Read Commited,而Spring配置的隔離級別是Repeatable Read,請問這時隔離級別是以哪一個為準?
答案是以 Spring 配置的為準。JDBC 有一個介面是這樣的:
意思就是,如果 Spring 定義的隔離級別和資料庫的不一樣,則以 Spring 定義的為準。
另外,如果 Spring 設定的隔離級別資料庫不支援,設定的效果取決於資料庫。
5. Spring 事務控制放在 Service 層,在 Service 方法中一個方法呼叫 Service 中的另一個方法,預設開啟幾個事務
此題考查的是 Spring 的事務傳播行為。
我們都知道,預設的傳播行為是 PROPAGATION_REQUIRED。如果外層有事務,則當前事務加入到外層事務,一起提交併一起回滾;如果外層沒有事務,新建一個事務執行。也就是說,預設情況下只有一個事務。
當然這種時候如果面試官繼續追問其他傳播行為的情形,該如何回答?
那我們應該把每種傳播機制都拿出來講一遍?沒必要,這種時候直接掀桌子走人。因為你就算背下來了過幾天還是會忘記,用到的時候再去查詢即可。
6. 怎麼保證 Spring 事務內的連線唯一性
這道題很多種問法,例如 Spring 是如何保證事務獲取的是同一個 Connection?
OK,開始我們的講解。其實答案只有一句話,因為那個 Connection 在事務開始時封裝在了 ThreadLocal 裡,後面事務執行過程中,都是從 ThreadLocal中 取的。肯定能保證唯一,因為都是在一個執行緒中執行。
至於程式碼,以J DBCTemplate的execute 方法為例,看看下面那張圖就懂了。
文末彩蛋
最新2020整理收集的一線網際網路公司面試真題(都整理成文件),有很多幹貨,包含netty,spring,執行緒,spring cloud等詳細講解,也有詳細的學習規劃圖,面試題整理等,我感覺在面試這塊講的非常清楚:獲取面試資料只需:點選這裡領取!!!暗號:CSDN
相關文章
- 面試官問我,使用Dubbo有沒有遇到一些坑?我笑了。面試
- 面試官問:Mybatis中的TypeHandler你用過嗎?面試MyBatis
- 記一次單例模式遇到的坑單例模式
- 對線面試官:通過MVCC資料庫事務的一致性面試MVC資料庫
- 對線面試官:透過MVCC資料庫事務的一致性面試MVC資料庫
- 【前端詞典】繼承(一) – 面試官問的你都會嗎?前端繼承面試
- 【前端詞典】繼承(一) - 面試官問的你都會嗎?前端繼承面試
- 問問那些變態的面試官面試
- 面試官問,你使用過命令模式嗎?我笑了!面試模式
- 面試官:你分析過SpringMVC的原始碼嗎?面試SpringMVC原始碼
- 面試官:Redis的事務滿足原子性嗎?面試Redis
- 面試時這麼問你Spring Boot,你能答對幾個?面試Spring Boot
- Spring Boot 面試,一個問題你就答不上來了Spring Boot面試
- 面試官:你知道哪些事務失效的場景?面試
- 面試官問你陣列和ArrayList怎麼答?面試陣列
- 面試官:給你一段有問題的SQL,如何最佳化?面試SQL
- 6道常見的python面試題,你答對了嗎?Python面試題
- 答面試官問:如何設計短url服務面試
- 面試官:你分析過mybatis工作原理嗎?面試MyBatis
- 當面試遇到 Redis,我作為一個面試官是這麼“刁難”你的!面試Redis
- 面試官:你還有什麼想問我的?面試
- 面試官一口氣問了MySQL事務、鎖和MVCC,我面試MySqlMVC
- 面試官:註解五問你怕了嗎?面試
- 【面試官問】你懂函數語言程式設計嗎?面試函數程式設計
- 異常處理遇到過的那些坑
- 一次電話面試題面試題
- 對線面試官:MySQL 事務、鎖和MVCC面試MySqlMVC
- 2019年一線大廠最全JVM面試100問!你能答對多少?JVM面試
- BATJ面試redis靈魂36問,你這麼回答,面試官一定對你刮目相看BAT面試Redis
- 面試官:請寫一個你認為比較“完美”的單例面試單例
- 面試中遇到的一些問題面試
- 面試問你為什麼要用Spring怎麼答?面試Spring
- [面試] 記錄一次來自 bigo 的電話面試面試Go
- 記一次版本升級遇到的坑
- 面試官問:你瞭解HTTP2.0嗎?面試HTTP
- 面試官問你:MYSQL事務和隔離級別,該如何回答面試MySql
- Spring事務(Transaction)管理高階篇一棧式解決開發中遇到的事務問題Spring
- 常見Linux運維面試題,你答對了嗎?Linux運維面試題