<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
開啟Spring事務本質上就是增加了一個Advisor,但我們使用 @EnableTransactionManagement註解來開啟Spring事務是,該註解代理的功能就是向Spring容器中新增了兩個Bean:
(1)AutoProxyRegistrar (2)ProxyTransactionManagementConfiguration
(1)AutoProxyRegistrar
主要的作用是向Spring容器中註冊了一個InfrastructureAdvisorAutoProxyCreator的Bean。
而InfrastructureAdvisorAutoProxyCreator繼承了AbstractAdvisorAutoProxyCreator,所以這個類的主要作用就是開啟自動代理的作用,也就是一個BeanPostProcessor,會在初始化後步驟中去尋找Advisor型別的Bean,並判斷當前某個Bean是否有匹配的Advisor,是否需要利用動態代理產生一個代理物件。
(2)ProxyTransactionManagementConfiguration是一個設定類,它又定義了另外三個bean:
bean | 定義 |
---|---|
BeanFactoryTransactionAttributeSourceAdvisor | 一個Advisor。 |
AnnotationTransactionAttributeSource | 相當於BeanFactoryTransactionAttributeSourceAdvisor中的Pointcut。就是用來判斷某個類上是否存在@Transactional註解,或者判斷某個方法上是否存在@Transactional註解的。 |
TransactionInterceptor | 相當於BeanFactoryTransactionAttributeSourceAdvisor中的Advice;就是代理邏輯,當某個類中存在@Transactional註解時,到時就產生一個代理物件作為Bean,代理物件在執行某個方法時,最終就會進入到TransactionInterceptor的invoke()方法。。 |
一個Bean在執行Bean的建立生命週期時,會經過InfrastructureAdvisorAutoProxyCreator的初始化後的方法,會判斷當前Bean物件是否BeanFactoryTransactionAttributeSourceAdvisor匹配,匹配邏輯為判斷該Bean的類上是否存在@Transactional註解,或者類中的某個方法上是否存在@Transactional註解,如果存在則表示該Bean需要進行動態代理產生一個代理物件作為Bean物件。
該代理物件在執行某個方法時,會再次判斷當前執行的方法是否和BeanFactoryTransactionAttributeSourceAdvisor匹配,如果匹配則執行該Advisor中的TransactionInterceptor的invoke()方法,
執行基本流程為:
利用所設定的PlatformTransactionManager事務管理器新建一個資料庫連線修改資料庫連線的autocommit為false執行MethodInvocation.proceed()方法,簡單理解就是執行業務方法,其中就會執行sql如果沒有拋異常,則提交如果拋了異常,則回滾 三、Spring事務的過程
1、資料庫:建立連線、開啟事務、進行sql操作、成功提交、失敗回滾
2、業務邏輯:準備工作(可以進行前置通知)、開啟事務、事務操作、成功提交(可以後置通知)、失敗回滾(異常通知)
spring的事務是由aop實現的,首先要生成具體的代理物件,然後按照aop流程執行具體
的操作邏輯,正常情況下要通過通知來完成核心功能,但是事務部署通過通知來實現的,
而是通過TransactionInterceptor來實現的,然後呼叫invoke來實現具體的邏輯。
步驟如下:
1、先做準備工作,解析各個方法上事務相關的屬性,根據具體的屬性來判斷是否開始新事務。
2、當需要開啟的時候獲取資料庫連線,關閉自動提交功能,開啟事務。
3、執行具體的sql邏輯操作,在操作的過程中如果執行失敗會通過 completeTransactionafterthrowing來完成事務的回滾操作,回滾的
具體邏輯是通過dorollback方法實現,實現時也要先獲取連線物件,
然後通過連線物件進行回滾(conn.rollback)。
4、如果執行成功,那麼通過completeTransactionafterrunning來完成事務的提交操作,
具體邏輯是通過docommit方法來實現,實現的時候也是先獲取連線,通過連線物件來
進行提交(conn.commit)。
5、最後事務執行完畢需要清除事務相關的事務資訊(cleanupTransactioninfo)。
在開發過程中,經常會出現一個方法呼叫另外一個方法,那麼這裡就涉及到了多種場景,比如a()呼叫b():
a()和b()方法中的所有sql需要在同一個事務中嗎?a()和b()方法中的所有sql需要在同一個事務中嗎?a()需要在事務中執行,b()還需要在事務中執行嗎?或者其他情況
這種情況下就要求Spring事務能支援上面各種場景,這就是Spring事務傳播機制的由來。
那Spring事務傳播機制是如何實現的呢?
先描述其中一個場景中情況,a()在一個事務中執行,呼叫b()方法時需要新開一個事務執行:
代理物件執行a()方法前,先利用事務管理器新建一個資料庫連線a將資料庫連線a的autocommit改為false把資料庫連線a設定到ThreadLocal中執行a()方法中的sql執行a()方法過程中,呼叫了b()方法(注意用代理物件呼叫b()方法)a()方法正常執行完,則從ThreadLocal中拿到資料庫連線a進行提交
關於步驟5的一些詳細解釋:
1、代理物件執行b()方法前,判斷出來了當前執行緒中已經存在一個資料庫連線a了,表示當前執行緒其實已經擁有一個Spring事務了,則進行掛起
2、掛起就是把ThreadLocal中的資料庫連線a從ThreadLocal中移除,並放入一個掛起資源物件中
3、掛起完成後,再次利用事務管理器新建一個資料庫連線b
4、將資料庫連線b的autocommit改為false
5、把資料庫連線b設定到ThreadLocal中
6、執行b()方法中的sql
7、b()方法正常執行完,則從ThreadLocal中拿到資料庫連線b進行提交
8、提交之後會恢復所掛起的資料庫連線a,這裡的恢復,其實只是把在掛起資源物件中所儲存的資料庫連線a再次設定到ThreadLocal中
過程中最為重要的是:在執行某個方法時,判斷當前是否已經存在一個事務,就是判斷當前執行緒的ThreadLocal中是否存在一個資料庫連線物件,如果存在則表示已經存在一個事務了。
在這裡面,以非事務方式執行,表示以非Spring事務執行,表示在執行這個方法時,Spring事務管理器不會去建立資料庫連線,執行sql時,由Mybatis或JdbcTemplate自己來建立資料庫連線來執行sql。
(1)案例分析、情況1
預設情況下傳播機制為REQUIRED,表示當前如果沒有事務則新建一個事務,如果有事務則在當前事務中執行。
@Component public class UserService { @Autowired private UserService userService; @Transactional public void test() { // test方法中的sql userService.a(); } @Transactional public void a() { // a方法中的sql } }
所以情況1的執行流程如下:
1、新建一個資料庫連線conn 2、設定conn的autocommit為false 3、執行test方法中的sql 4、執行a方法中的sql 5、執行conn的commit()方法進行提交
(2)案例分析、情況2
如果是這種情況:
@Component public class UserService { @Autowired private UserService userService; @Transactional public void test() { // test方法中的sql userService.a(); int result = 100/0; } @Transactional public void a() { // a方法中的sql } }
所以情況2的執行流程如下:
1、新建一個資料庫連線conn 2、設定conn的autocommit為false 3、執行test方法中的sql 4、執行a方法中的sql 5、丟擲異常 6、執行conn的rollback()方法進行回滾,所以兩個方法中的sql都會回滾掉
(3)案例分析、情況3
@Component public class UserService { @Autowired private UserService userService; @Transactional public void test() { // test方法中的sql userService.a(); } @Transactional public void a() { // a方法中的sql int result = 100/0; } }
所以情況3的執行流程如下:
1、新建一個資料庫連線conn 2、設定conn的autocommit為false 3、執行test方法中的sql 4、執行a方法中的sql 5、丟擲異常 6、執行conn的rollback()方法進行回滾,所以兩個方法中的sql都會回滾掉
(4)案例分析、情況4
@Component public class UserService { @Autowired private UserService userService; @Transactional public void test() { // test方法中的sql userService.a(); } @Transactional(propagation = Propagation.REQUIRES_NEW) public void a() { // a方法中的sql int result = 100/0; } }
所以情況3的執行流程如下:
1、新建一個資料庫連線conn 2、設定conn的autocommit為false 3、執行test方法中的sql 4、又新建一個資料庫連線conn2 5、執行a方法中的sql 6、丟擲異常 7、執行conn2的rollback()方法進行回滾 8、繼續拋異常,對於test()方法而言,它會接收到一個異常,然後丟擲 9、執行conn的rollback()方法進行回滾,最終還是兩個方法中的sql都回滾了
正常情況下,a()呼叫b()方法時,如果b()方法拋了異常,但是a()方法捕獲了,那麼a()的事務還是會正常提交的,但是有的時候,我們捕獲異常可能只是不把異常資訊返回給使用者端,而是為了返回一些更優良的錯誤資訊,所以在這個時候,我們還是希望事務能回滾的,那就得告訴Spring把當前事務回滾掉,做法就是:
@Transactional public void test(){ // 執行sql try { b(); } catch (Exception e) { // 構造友好的錯誤資訊返回 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); } } public void b() throws Exception { throw new Exception(); }
Spring事務有可能會提交,回滾、掛起、恢復,所以Spring事務提供了一種機制,可以讓程式設計師來監聽當前Spring事務所處於的狀態。
@Component public class UserService { @Autowired private JdbcTemplate jdbcTemplate; @Autowired private UserService userService; @Transactional public void test(){ TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { @Override public void suspend() { System.out.println("test被掛起"); } @Override public void resume() { System.out.println("test被恢復"); } @Override public void beforeCommit(boolean readOnly) { System.out.println("test準備要提交"); } @Override public void beforeCompletion() { System.out.println("test準備要提交或回滾"); } @Override public void afterCommit() { System.out.println("test提交成功"); } @Override public void afterCompletion(int status) { System.out.println("test提交或回滾成功"); } }); jdbcTemplate.execute("insert into t1 values(1,1,1,1,'1')"); System.out.println("test"); userService.a(); } @Transactional(propagation = Propagation.REQUIRES_NEW) public void a(){ TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { @Override public void suspend() { System.out.println("a被掛起"); } @Override public void resume() { System.out.println("a被恢復"); } @Override public void beforeCommit(boolean readOnly) { System.out.println("a準備提交"); } @Override public void beforeCompletion() { System.out.println("a準備提交或回滾"); } @Override public void afterCommit() { System.out.println("a提交成功"); } @Override public void afterCompletion(int status) { System.out.println("a提交或回滾成功"); } }); jdbcTemplate.execute("insert into t1 values(2,2,2,2,'2')"); System.out.println("a"); } }
到此這篇關於Spring底層事務原理的文章就介紹到這了,更多相關Spring底層事務原理內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45