一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - Spring數據庫事務的實現機制講解

Spring數據庫事務的實現機制講解

2022-02-12 15:31不去天涯 Java教程

這篇文章主要介紹了Spring數據庫事務的實現機制講解,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

事務控制的核心——Connection

在開始之前,先讓我們回憶一下數據庫較原始的JDBC是怎么管理事務的:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//僅做演示,代碼不完整,不完全規范
try {
    con.setAutoCommit(false);
    statement1 = con.prepareStatement(sql);
    statement1.executeUpdate();
    statement2 = con.prepareStatement(sql1);
    statement2.executeUpdate();
    con.commit();
} catch (SQLException e) {
    try {
        con.rollback();
    } catch (SQLException e1) {
    }
}

可以很明顯的看到,JDBC框架下的事務控制是由connection完成的。因為不論是MyBatis還是MyBatis-Spring都是在JDBC框架基礎上的高層框架,所以他們的原理仍然應該是一致的,也就是說想控制事務,必須要控制Connection。

我們常說事務要切在Service層,所以連接需要在整個Service請求中都是同一個,不能變。

用AOP技術保持當前的Connection

Spring的事務管理就是使用AOP技術,通過對Service層設置切面,注入事務管理的邏輯。

Spring的事務管理切面配置采用了聲明式事務,最常用的兩種方法是 tx:Advice 和 tx:annotation-driven 兩種方式。

兩種方式的配置文件解析器分別是:

org.springframework.transaction.config.TxAdviceBeanDefinitionParser

org.springframework.transaction.config.AnnotationDrivenBeanDefinitionParser

細看其中的代碼和配置內容,就會發現,不論哪種方式都會創建包含事務處理功能的動態代理。代理關聯的切面(Advice)類是 TransactionInterceptor 。

一起看下關鍵代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
   protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)
            throws Throwable {
        //......
        if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
            TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);//-----1.開啟事務
            Object retVal = null;
            try {
                retVal = invocation.proceedWithInvocation();//...2.執行被代理的請求
            }
            catch (Throwable ex) {
completeTransactionAfterThrowing(txInfo, ex);//...3.異常回滾
                throw ex;
            }
            finally {
                cleanupTransactionInfo(txInfo);
            }
            commitTransactionAfterReturning(txInfo);//...4.提交事務
            return retVal;
        }
        //......

上邊的代碼里是不是沒有看到TransactionManger和Connection?那么這兩個東西的作用在哪里呢?

TransactionManger是上述TransactionInterceptor的一個屬性(不嚴的說),主要作用是用來創建connection,創建之后的Connection會被保存在TransactionInfo里面。

TransactionInfo在上述代碼片段中被后續傳遞給事務提交和事務回滾的代碼。

Service層和Dao層共享Connection

我們都知道事務要切在Service層,也就是說上一節的切面只是在Service層有效,那么Dao層怎么獲取到Connection連接呢?

如果Service層和Dao層的連接不是一個連接那么回滾和提交操作就等同于無效了!

這里只用MyBatis來說明,其他的ORM框架實現原理基本也是一樣的。

要明白這一點需要先弄明白MyBatis本身的事務管理機制,可以參考MyBatis源碼解析之Transaction事務模塊。MyBatis提供了兩種事務管理機制一種是自己內部用的JDBC模式,一種是支持代理給外部控制的MANAGED模式。

第二種模式下會把事務的交給外部控制,外部只需要提供一個實現了 org.apache.ibatis.transaction.Transaction 接口的控制類即可。

一起來看一下Transaction需要提供哪些方法:

?
1
2
3
4
5
6
public interface Transaction {
  Connection getConnection() throws SQLException;
  void commit() throws SQLException;
  void rollback() throws SQLException;
  void close() throws SQLException;
}

注意里邊的getConnection方法,也就是說MyBatis的連接也是交給外部來獲取的!!那么只需要想辦法把Service層的Connection存起來,然后讓自己實現Transaction獲取到即可。

Spring采用的是ThreadLocal本地線程變量的技術來做到的,我們可以看下mybatis-spring的 org.mybatis.spring.transaction.SpringManagedTransaction 中getConnection的實現就明白了:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public Connection getConnection() throws SQLException {
  if (this.connection == null) {
    openConnection();
  }
  return this.connection;
}
 
private void openConnection() throws SQLException {
  this.connection = DataSourceUtils.getConnection(this.dataSource);//...1.關鍵點在這里!!
  this.autoCommit = this.connection.getAutoCommit();
  this.isConnectionTransactional = DataSourceUtils.isConnectionTransactional(this.connection, this.dataSource);
  if (LOGGER.isDebugEnabled()) {
    LOGGER.debug(
        "JDBC Connection ["
            + this.connection
            + "] will"
            + (this.isConnectionTransactional ? " " : " not ")
            + "be managed by Spring");
  }
}

其中

?
1
this.connection = DataSourceUtils.getConnection(this.dataSource);

一行就會從ThreadLocal中拿到Connection對象。

事務為什么要切在Service層的理由

對于這個常識,有一點個人的理解:

事務的ACID要求事務要有原子性,也就是一個事務里邊的多項DB操作要同時成功,同時失敗,成功一半的情況是不允許的。

也就是說,一般需要事務的時候,都是包含多個功能單元的。那么我們都放在一個Dao里面就顯得不那么職能分明,也就是不那么符合設計原則的單一職責原則。

spring事務與數據庫事務的區別

先說一下什么是事務,事務(Transaction):

一般是指要做的或所做的事情。在計算機術語中是指訪問并可能更新數據庫中各種數據項的一個程序執行單元(unit)。事務通常由高級數據庫操縱語言或編程語言(如SQL,C++或Java)書寫的用戶程序的執行所引起,并用形如begin transaction和end transaction語句(或函數調用)來界定。事務由事務開始(begin transaction)和事務結束(end transaction)之間執行的全體操作組成。。

之前一直覺得事務只針對于數據庫當中,5種隔離級別,7種傳播行為,后來才發現這是針對Spring的,對數據庫來說隔離級別只有4種,Spring多了一個DEFAULT 這是一個PlatfromTransactionManager默認的隔離級別,使用數據庫默認的事務隔離級別.

總的來說,本質上其實是同一個概念

spring的事務是對數據庫的事務的封裝,最后本質的實現還是在數據庫,假如數據庫不支持事務的話,spring的事務是沒有作用的

數據庫的事務說簡單就只有開啟,回滾和關閉,spring對數據庫事務的包裝,原理就是拿一個數據連接,根據spring的事務配置,操作這個數據連接對數據庫進行事務開啟,回滾或關閉操作.但是spring除了實現這些,還配合spring的傳播行為對事務進行了更廣泛的管理.其實這里還有個重要的點,那就是事務中涉及的隔離級別,以及spring如何對數據庫的隔離級別進行封裝.事務與隔離級別放在一起理解會更好些。

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持服務器之家。

原文鏈接:https://buqutianya.blog.csdn.net/article/details/78946473

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 精品一久久香蕉国产二月 | 亚洲人成伊人成综合网久久 | 久久久久综合 | 69成人影院 | 加勒比一本大道香蕉在线视频 | 91动漫在线观看 | 暖暖在线精品日本中文 | chinese男同志gay免费 | 亚洲欧洲综合 | 任你操视频在线观看 | 欧美一级视频在线观看 | 非洲黑人bbwbbwbbw | 色综合中文字幕天天在线 | 女人张开腿 让男人桶个爽 免费观看 | 欧美日日操 | 18日本人| 国产成人高清精品免费观看 | 成年性香蕉漫画在线观看 | 精品国产91久久久久 | 亚洲视频中文 | 国产外围| 久热这里只有精品99国产6 | 亚洲高清一区二区三区久久 | 国产成人小视频在线观看 | 亚洲高清毛片一区二区 | 国产日韩欧美色视频色在线观看 | 四虎影院在线免费观看视频 | 精品无人区麻豆乱码1区2 | 99热这里有免费国产精品 | 亚洲国产综合久久精品 | 欧美xxxxx九色视频免费观看 | 私人黄色| 日韩理论片在线看免费观看 | 日本大尺度激情做爰叫床 | 精品国产免费观看一区高清 | 久久伊人中文字幕有码 | 国产里番 | 国产精品福利短视在线播放频 | 欧美一卡2卡3卡四卡海外精品 | 亚洲va欧美va天堂v国产综合 | 青青久久精品国产免费看 |