欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

MyBatis源碼解析之Transaction事務(wù)模塊

 更新時(shí)間:2021年10月08日 14:43:52   作者:唯一浩哥  
這篇文章主要介紹了MyBatis源碼解析之Transaction事務(wù)模塊,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

1、回顧

之前介紹了Environment環(huán)境類,這其實(shí)是一個(gè)單例類,在MyBatis運(yùn)行開(kāi)啟后只會(huì)存在一個(gè)唯一的環(huán)境實(shí)例,雖然我們可以在Configuration配置文件中配置多個(gè)環(huán)境,但是項(xiàng)目運(yùn)行中只會(huì)存在其中的一個(gè),一般項(xiàng)目會(huì)存在開(kāi)發(fā)環(huán)境和測(cè)試環(huán)境、生產(chǎn)環(huán)境三大環(huán)境,其是否可以設(shè)置到配置文件中,在開(kāi)發(fā)時(shí)使用開(kāi)發(fā)環(huán)境,測(cè)試時(shí)使用測(cè)試環(huán)境,正式運(yùn)營(yíng)時(shí)可以使用生產(chǎn)環(huán)境。

之前還提到Environment類中有三個(gè)字段,除了id之外,TransactionFactory和DataSource都是比較復(fù)雜的模塊,這一次我們介紹Transaction模塊(即事務(wù)模塊)。

2、事務(wù)模塊

事務(wù)模塊位于org.apache.ibatis.transaction包,這個(gè)包內(nèi)的類均是事務(wù)相關(guān)的類:

  org.apache.ibatis.transaction
  -----org.apache.ibatis.transaction.jdbc
  ----------JdbcTransaction.java
  ----------JdbcTransactionFactory.java
  -----org.apache.ibatis.transaction.managed
  ----------ManagedTransaction.java
  ----------ManagedTransactionFactory.java
  -----Transaction.java
  -----TransactionException.java
  -----TransactionFactory.java

從上面的類結(jié)構(gòu)中也能看出來(lái),MyBatis的事務(wù)模塊采用的是工廠模式。

2.1 事務(wù)接口

位于org.apache.ibatis.transaction包的Transaction和TransactionFactory都是接口類。

Transaction是事務(wù)接口,其中定義了四個(gè)方法:

  • commit()-事務(wù)提交
  • rollBack()-事務(wù)回滾
  • close()-關(guān)閉數(shù)據(jù)庫(kù)連接
  • getConnection()-獲取數(shù)據(jù)庫(kù)連接

如下代碼所示:

package org.apache.ibatis.transaction;
import java.sql.Connection;
import java.sql.SQLException;
/**
 * 事務(wù),包裝了一個(gè)Connection, 包含commit,rollback,close方法
 * 在 MyBatis 中有兩種事務(wù)管理器類型(也就是 type=”[JDBC|MANAGED]”):  
 */
public interface Transaction {
  Connection getConnection() throws SQLException;
 void commit() throws SQLException;
 void rollback() throws SQLException;
 void close() throws SQLException;
}

TransactionFactory是事務(wù)工廠接口,其中定義了三個(gè)方法:

  • setProperties(Properties props)-設(shè)置屬性
  • newTransaction(Connection conn)-創(chuàng)建事務(wù)實(shí)例
  • newTransaction(DataSource dataSource,TransactionIsolationLevel level,boolean autoCommit)-創(chuàng)建事務(wù)實(shí)例

如下代碼所示:

package org.apache.ibatis.transaction;
import java.sql.Connection;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.ibatis.session.TransactionIsolationLevel;
/**
 * 事務(wù)工廠
 */
public interface TransactionFactory {
 //設(shè)置屬性
 void setProperties(Properties props);
 //根據(jù)Connection創(chuàng)建Transaction
 Transaction newTransaction(Connection conn);
 //根據(jù)數(shù)據(jù)源和事務(wù)隔離級(jí)別創(chuàng)建Transaction
 Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit);
}

Transacrion接口定義的目的就是為了對(duì)具體的事務(wù)類型進(jìn)行抽象,便于擴(kuò)展;TransactionFactory與其一樣,是對(duì)事務(wù)工廠的抽象,同樣便于具體類型的事務(wù)工廠的擴(kuò)展實(shí)現(xiàn)。

2.2 MyBatis事務(wù)類型

說(shuō)到這里,就不得不提到MyBatis里內(nèi)置的兩種事務(wù)類型及對(duì)應(yīng)的事務(wù)工廠了,還記得在上一文中給出的environment配置信息,有這么一句:

 <transactionManager type="JDBC"/>

這里的<transactionManager>標(biāo)簽就是用于定義項(xiàng)目所使用的事務(wù)類型,具體的類型由type屬性來(lái)指定,此處指定使用“JDBC”類型事務(wù),當(dāng)然MyBatis還提供了另外一種“MANAGED”型事務(wù)。

  • ---JDBC
  • ---MANAGED

這里的“JDBC”和“MANAGED”是在Configuration配置類的類型別名注冊(cè)器中注冊(cè)的別名,其對(duì)應(yīng)的類分別是:JdbcTransactionFactory.class和ManagedTransactionFactory.class。具體的配置如下所述:

typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);

上面的代碼是在Configuration類的無(wú)參構(gòu)造器中定義的,這里拿來(lái)僅用于展示,具體說(shuō)明以后會(huì)介紹。

這里提一句:類型別名注冊(cè)器額原理就是將別名與具體的類類型以鍵值對(duì)的方式保存到一個(gè)HashMap中,這樣只要知道別名(鍵),就可以從Map中得到對(duì)應(yīng)的值(Class類型),很簡(jiǎn)單!

現(xiàn)在只要知道MyBatis能夠根據(jù)你在配置文件中設(shè)置的事務(wù)類型,直接找到對(duì)應(yīng)的事務(wù)工廠類就行了。

下面對(duì)上面提到的兩種事務(wù)類型進(jìn)行解讀。

  • ---JDBC事務(wù)模型:JdbcTransaction
  • ---MANAFED事務(wù)模型:ManagedTransaction

二者的不同之處在于:前者是直接使用JDK提供的JDBC來(lái)管理事務(wù)的各個(gè)環(huán)節(jié):提交、回滾、關(guān)閉等操作,而后者則什么都不做,那么后者有什么意義呢,當(dāng)然很重要?!?/p>

當(dāng)我們單獨(dú)使用MyBatis來(lái)構(gòu)建項(xiàng)目時(shí),我們要在Configuration配置文件中進(jìn)行環(huán)境(environment)配置,在其中要設(shè)置事務(wù)類型為JDBC,意思是說(shuō)MyBatis被單獨(dú)使用時(shí)就需要使用JDBC類型的事務(wù)模型,因?yàn)樵谶@個(gè)模型中定義了事務(wù)的各個(gè)方面,使用它可以完成事務(wù)的各項(xiàng)操作。

而MANAGED類型的事務(wù)模型其實(shí)是一個(gè)托管模型,也就是說(shuō)它自身并不實(shí)現(xiàn)任何事務(wù)功能,而是托管出去由其他框架來(lái)實(shí)現(xiàn),你可能還不明白,這個(gè)事務(wù)的具體實(shí)現(xiàn)就交由如Spring之類的框架來(lái)實(shí)現(xiàn),而且在使用SSM整合框架后已經(jīng)不再需要單獨(dú)配置環(huán)境信息(包括事務(wù)配置與數(shù)據(jù)源配置),因?yàn)樵谠谡蟡ar包(mybatis-spring.jar)中擁有覆蓋mybatis里面的這部分邏輯的代碼,實(shí)際情況是即使你顯式設(shè)置了相關(guān)配置信息,系統(tǒng)也會(huì)視而不見(jiàn)......

托管的意義顯而易見(jiàn),正是為整合而設(shè)。

我們學(xué)習(xí)MyBatis的目的正是由于其靈活性和與Spring等框架的無(wú)縫整合的能力,所以有關(guān)JDBC事務(wù)模塊的內(nèi)容明顯不再是MyBatis功能中的重點(diǎn),也許只有在單獨(dú)使用MyBatis的少量系統(tǒng)中才會(huì)使用到。

2.3 JDBC事務(wù)模型

雖然JDBC事務(wù)類型很少使用到,但是作為MyBatis不可分割的一部分,我們還是需要進(jìn)行一定的了解,JDBC事務(wù)的實(shí)現(xiàn)是對(duì)JDK中提供的JDBC事務(wù)模塊的再封裝,以適用于MyBatis環(huán)境。

MyBatis中的JDBC事務(wù)模塊包括兩個(gè)部分,分別為JDBC事務(wù)工廠和JDBC事務(wù),整個(gè)事務(wù)模塊采用的是抽象工廠模式,那么對(duì)應(yīng)于每一項(xiàng)具體的事務(wù)處理模塊必然擁有自己的事務(wù)工廠,事務(wù)模塊實(shí)例通過(guò)事務(wù)工廠來(lái)創(chuàng)建(事務(wù)工廠將具體的事務(wù)實(shí)例的創(chuàng)建封裝起來(lái))。

首先我們來(lái)看JDBC事務(wù)工廠:JdbcTransactionFactory

JdbcTransactionFactory繼承自TransactionFactory接口,實(shí)現(xiàn)了其中的所有方法。分別為一個(gè)設(shè)置屬性的方法和兩個(gè)新建事務(wù)實(shí)例的方法(參數(shù)不同),內(nèi)容很簡(jiǎn)單,作用也很簡(jiǎn)單。

其中setProperties()方法用于設(shè)置屬性,這個(gè)方法在XMLConfigBuilder中解析事務(wù)標(biāo)簽時(shí)調(diào)用,用于解析事務(wù)標(biāo)簽的下級(jí)屬性標(biāo)簽<property>(一般情況下我們并不會(huì)進(jìn)行設(shè)置,但是如果我們進(jìn)行了設(shè)置,那就會(huì)覆蓋MyBatis中的默認(rèn)設(shè)置)之后將其設(shè)置到創(chuàng)建的事務(wù)實(shí)例中。然而針對(duì)JDBC事務(wù)模型,在事務(wù)工廠的設(shè)置屬性方法中沒(méi)有任何執(zhí)行代碼,也就說(shuō)明JDBC事務(wù)模塊并不支持設(shè)置屬性的功能,即使你在配置文件中設(shè)置的一些信息,也不會(huì)有任何作用。

那么這個(gè)方法有什么用呢?前面提到,這個(gè)設(shè)置用于覆蓋默認(rèn)設(shè)置,只是JDBC事務(wù)模塊并不支持而已,但并不代表別的事務(wù)模型不支持,同時(shí)這個(gè)方法也可用于功能擴(kuò)展。

另外兩個(gè)方法顯而易見(jiàn),就是用于創(chuàng)建JDBC事務(wù)實(shí)例的生產(chǎn)方法,只是參數(shù)不同,方法的重載而已。其中一個(gè)生產(chǎn)方法僅需傳遞一個(gè)實(shí)例Connection,這代表一個(gè)數(shù)據(jù)庫(kù)連接。而另一個(gè)方法需要傳遞三個(gè)參數(shù)(DataSource、TransactionIsolationLevel、boolean),其實(shí)這對(duì)應(yīng)于MyBatis中SqlSession的兩種生產(chǎn)方式,其參數(shù)與這里一一對(duì)應(yīng),這部分內(nèi)容以后介紹,此處不再贅述。

然后我們來(lái)看看JDBC事務(wù)類:JdbcTransaction

其中有四個(gè)參數(shù):

 protected Connection connection;
 protected DataSource dataSource;
 protected TransactionIsolationLevel level;
 protected boolean autoCommmit;

這四個(gè)參數(shù)分別對(duì)應(yīng)事務(wù)工廠中的兩個(gè)生產(chǎn)方法中的總共四個(gè)參數(shù),對(duì)應(yīng)的在事務(wù)類中定義了兩個(gè)構(gòu)造器,構(gòu)造實(shí)例的同時(shí)進(jìn)行賦值:

public JdbcTransaction(DataSource ds, TransactionIsolationLevel desiredLevel, boolean desiredAutoCommit) {
   dataSource = ds;
   level = desiredLevel;
   autoCommmit = desiredAutoCommit;
 }
 public JdbcTransaction(Connection connection) {
   this.connection = connection;
 }

其次在該類中實(shí)現(xiàn)了Transaction接口,實(shí)現(xiàn)了其中的四個(gè)方法,三個(gè)功能性方法,和一個(gè)獲取數(shù)據(jù)庫(kù)連接的方法。三個(gè)功能方法分別是提交、回滾和關(guān)閉。

  @Override
  public void commit() throws SQLException {
    if (connection != null && !connection.getAutoCommit()) {
      if (log.isDebugEnabled()) {
        log.debug("Committing JDBC Connection [" + connection + "]");
      }
      connection.commit();
    }
  }

 @Override
 public void rollback() throws SQLException {
   if (connection != null && !connection.getAutoCommit()) {
     if (log.isDebugEnabled()) {
       log.debug("Rolling back JDBC Connection [" + connection + "]");
     }
     connection.rollback();
   }
 }

 @Override
 public void close() throws SQLException {
   if (connection != null) {
     resetAutoCommit();
     if (log.isDebugEnabled()) {
       log.debug("Closing JDBC Connection [" + connection + "]");
     }
     connection.close();
   }
 }

通過(guò)觀察這三個(gè)方法,可以發(fā)現(xiàn),其中都使用了connection來(lái)進(jìn)行具體操作,因此這些方法使用的前提就是先獲取connection數(shù)據(jù)庫(kù)連接,Connection的獲取使用getConnection()方法

 @Override
 public Connection getConnection() throws SQLException {
   if (connection == null) {
     openConnection();
   }
   return connection;
 }

在上面的方法中調(diào)用了openConnection()方法:

 protected void openConnection() throws SQLException {
    if (log.isDebugEnabled()) {
      log.debug("Opening JDBC Connection");
    }
    connection = dataSource.getConnection();
    if (level != null) {
      connection.setTransactionIsolation(level.getLevel());
    }
    setDesiredAutoCommit(autoCommmit);
 }

可見(jiàn)connection是從數(shù)據(jù)源dataSource中獲取的,最后會(huì)調(diào)用setDesiredAutoCommit()方法:

  protected void setDesiredAutoCommit(boolean desiredAutoCommit) {
    try {
      if (connection.getAutoCommit() != desiredAutoCommit) {
        if (log.isDebugEnabled()) {
          log.debug("Setting autocommit to " + desiredAutoCommit + " on JDBC Connection [" + connection + "]");
        }
        connection.setAutoCommit(desiredAutoCommit);
      }
    } catch (SQLException e) {
     // Only a very poorly implemented driver would fail here,
     // and there's not much we can do about that.
     throw new TransactionException("Error configuring AutoCommit.  "
         + "Your driver may not support getAutoCommit() or setAutoCommit(). "
         + "Requested setting: " + desiredAutoCommit + ".  Cause: " + e, e);
   }
 }

這個(gè)方法的目的就是為connection中的自動(dòng)提交賦值(真或假)。

這么看來(lái),我們創(chuàng)建事務(wù)實(shí)例所提供的三個(gè)參數(shù)就是為connection服務(wù)的,其中DataSource是用來(lái)獲取Connection實(shí)例的,而TransactionIsolationLevel(事務(wù)級(jí)別)和boolean(自動(dòng)提交)是用來(lái)填充connection的,通過(guò)三個(gè)參數(shù)我們獲得了一個(gè)圓滿的Connection實(shí)例,然后我們就可以使用這個(gè)實(shí)例來(lái)進(jìn)行事務(wù)操作:提交、回滾、關(guān)閉。

2.4 關(guān)于自動(dòng)提交

在之前的代碼中我們能看到在關(guān)閉操作之前調(diào)用了一個(gè)方法:resetAutoCommit():

 protected void resetAutoCommit() {
   try {
     if (!connection.getAutoCommit()) {
       // MyBatis does not call commit/rollback on a connection if just selects were performed.
       // Some databases start transactions with select statements
       // and they mandate a commit/rollback before closing the connection.
       // A workaround is setting the autocommit to true before closing the connection.
       // Sybase throws an exception here.
       if (log.isDebugEnabled()) {
        log.debug("Resetting autocommit to true on JDBC Connection [" + connection + "]");
      }
      connection.setAutoCommit(true);
    }
  } catch (SQLException e) {
    log.debug("Error resetting autocommit to true "
        + "before closing the connection.  Cause: " + e);
  }
}

這里相對(duì)自動(dòng)提交做個(gè)解說(shuō),如果設(shè)置自動(dòng)提交為真,那么數(shù)據(jù)庫(kù)將會(huì)將每一個(gè)SQL語(yǔ)句當(dāng)做一個(gè)事務(wù)來(lái)執(zhí)行,為了將多條SQL當(dāng)做一個(gè)事務(wù)進(jìn)行提交,必須將自動(dòng)提交設(shè)置為false,然后進(jìn)行手動(dòng)提交。一般在我們的項(xiàng)目中,都需要將自動(dòng)提交設(shè)置為false,即將自動(dòng)提交關(guān)閉,使用手動(dòng)提交

這個(gè)方法中通過(guò)對(duì)connection實(shí)例中的自動(dòng)提交設(shè)置(真或假)進(jìn)行判斷,如果為false,表明不執(zhí)行自動(dòng)提交,則復(fù)位,重新將其設(shè)置為true。(自動(dòng)提交的默認(rèn)值為true)這個(gè)操作執(zhí)行在connection關(guān)閉之前。可以看做是連接關(guān)閉之前的復(fù)位操作。

2.5 問(wèn)題

在JdbcTransaction中提供的兩個(gè)構(gòu)造器中以Connection為參數(shù)的構(gòu)造器額作用是什么呢?

我們需要自動(dòng)組裝一個(gè)完整的Connection,以其為參數(shù)來(lái)生產(chǎn)一個(gè)事務(wù)實(shí)例。這用在什么場(chǎng)景中呢?

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Spring?JPA?deleteInBatch導(dǎo)致StackOverflow問(wèn)題

    Spring?JPA?deleteInBatch導(dǎo)致StackOverflow問(wèn)題

    這篇文章主要介紹了Spring?JPA?deleteInBatch導(dǎo)致StackOverflow問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • spring boot項(xiàng)目使用@JsonFormat失效問(wèn)題的解決

    spring boot項(xiàng)目使用@JsonFormat失效問(wèn)題的解決

    這篇文章主要介紹了spring boot項(xiàng)目使用@JsonFormat失效問(wèn)題的解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • java實(shí)現(xiàn)學(xué)生成績(jī)信息管理系統(tǒng)

    java實(shí)現(xiàn)學(xué)生成績(jī)信息管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)學(xué)生成績(jī)信息管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-07-07
  • IDEA生成servlet程序的實(shí)現(xiàn)步驟

    IDEA生成servlet程序的實(shí)現(xiàn)步驟

    這篇文章主要介紹了IDEA生成servlet程序的實(shí)現(xiàn)步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • SpringBoot靜態(tài)資源與首頁(yè)配置實(shí)現(xiàn)原理深入分析

    SpringBoot靜態(tài)資源與首頁(yè)配置實(shí)現(xiàn)原理深入分析

    最近在做SpringBoot項(xiàng)目的時(shí)候遇到了“白頁(yè)”問(wèn)題,通過(guò)查資料對(duì)SpringBoot訪問(wèn)靜態(tài)資源做了總結(jié),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧
    2022-10-10
  • Spring Boot中如何使用Swagger詳解

    Spring Boot中如何使用Swagger詳解

    Swagger是一個(gè)規(guī)范和完整的框架,用于生成、描述、調(diào)用和可視化 RESTful風(fēng)格的Web服務(wù),這篇文章主要給大家介紹了關(guān)于Spring Boot中如何使用Swagger的相關(guān)資料,需要的朋友可以參考下
    2021-08-08
  • Java實(shí)現(xiàn)用位運(yùn)算維護(hù)狀態(tài)碼

    Java實(shí)現(xiàn)用位運(yùn)算維護(hù)狀態(tài)碼

    位運(yùn)算是一種非常高效的運(yùn)算方式,在算法考察中比較常見(jiàn),那么業(yè)務(wù)代碼中我們?nèi)绾问褂梦贿\(yùn)算呢,感興趣的小伙伴快跟隨小編一起學(xué)習(xí)一下吧
    2024-03-03
  • 解決IDEA service層跳轉(zhuǎn)實(shí)現(xiàn)類的快捷圖標(biāo)消失問(wèn)題

    解決IDEA service層跳轉(zhuǎn)實(shí)現(xiàn)類的快捷圖標(biāo)消失問(wèn)題

    這篇文章主要介紹了解決IDEA service層跳轉(zhuǎn)實(shí)現(xiàn)類的快捷圖標(biāo)消失問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-02-02
  • 詳解Mybatis極其(最)簡(jiǎn)(好)單(用)的一個(gè)分頁(yè)插件

    詳解Mybatis極其(最)簡(jiǎn)(好)單(用)的一個(gè)分頁(yè)插件

    這篇文章主要介紹了詳解Mybatis極其(最)簡(jiǎn)(好)單(用)的一個(gè)分頁(yè)插件,非常具有實(shí)用價(jià)值,需要的朋友可以參考下。
    2016-12-12
  • Java服務(wù)器主機(jī)信息監(jiān)控工具類的示例代碼

    Java服務(wù)器主機(jī)信息監(jiān)控工具類的示例代碼

    這篇文章主要介紹了Java服務(wù)器主機(jī)信息監(jiān)控工具類的示例代碼,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-04-04

最新評(píng)論