最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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)行開啟后只會(huì)存在一個(gè)唯一的環(huán)境實(shí)例,雖然我們可以在Configuration配置文件中配置多個(gè)環(huán)境,但是項(xiàng)目運(yùn)行中只會(huì)存在其中的一個(gè),一般項(xiàng)目會(huì)存在開發(fā)環(huán)境和測(cè)試環(huán)境、生產(chǎn)環(huán)境三大環(huán)境,其是否可以設(shè)置到配置文件中,在開發(fā)時(shí)使用開發(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)中也能看出來,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ù)類型

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

 <transactionManager type="JDBC"/>

這里的<transactionManager>標(biāo)簽就是用于定義項(xiàng)目所使用的事務(wù)類型,具體的類型由type屬性來指定,此處指定使用“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類的無參構(gòu)造器中定義的,這里拿來僅用于展示,具體說明以后會(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來管理事務(wù)的各個(gè)環(huán)節(jié):提交、回滾、關(guān)閉等操作,而后者則什么都不做,那么后者有什么意義呢,當(dāng)然很重要?!?/p>

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

而MANAGED類型的事務(wù)模型其實(shí)是一個(gè)托管模型,也就是說它自身并不實(shí)現(xiàn)任何事務(wù)功能,而是托管出去由其他框架來實(shí)現(xiàn),你可能還不明白,這個(gè)事務(wù)的具體實(shí)現(xiàn)就交由如Spring之類的框架來實(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ì)視而不見......

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

我們學(xué)習(xí)MyBatis的目的正是由于其靈活性和與Spring等框架的無縫整合的能力,所以有關(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í)例通過事務(wù)工廠來創(chuàng)建(事務(wù)工廠將具體的事務(wù)實(shí)例的創(chuàng)建封裝起來)。

首先我們來看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è)置屬性方法中沒有任何執(zhí)行代碼,也就說明JDBC事務(wù)模塊并不支持設(shè)置屬性的功能,即使你在配置文件中設(shè)置的一些信息,也不會(huì)有任何作用。

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

另外兩個(gè)方法顯而易見,就是用于創(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)容以后介紹,此處不再贅述。

然后我們來看看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();
   }
 }

通過觀察這三個(gè)方法,可以發(fā)現(xiàn),其中都使用了connection來進(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);
 }

可見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)提交賦值(真或假)。

這么看來,我們創(chuàng)建事務(wù)實(shí)例所提供的三個(gè)參數(shù)就是為connection服務(wù)的,其中DataSource是用來獲取Connection實(shí)例的,而TransactionIsolationLevel(事務(wù)級(jí)別)和boolean(自動(dòng)提交)是用來填充connection的,通過三個(gè)參數(shù)我們獲得了一個(gè)圓滿的Connection實(shí)例,然后我們就可以使用這個(gè)實(shí)例來進(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è)解說,如果設(shè)置自動(dòng)提交為真,那么數(shù)據(jù)庫(kù)將會(huì)將每一個(gè)SQL語(yǔ)句當(dāng)做一個(gè)事務(wù)來執(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è)方法中通過對(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 問題

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

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

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

  • Java生成MD5加密字符串代碼實(shí)例

    Java生成MD5加密字符串代碼實(shí)例

    這篇文章主要介紹了Java生成MD5加密字符串代碼實(shí)例,本文對(duì)MD5的作用作了一些介紹,然后給出了Java下生成MD5加密字符串的代碼示例,需要的朋友可以參考下
    2015-06-06
  • 在實(shí)踐中了解Java反射機(jī)制應(yīng)用

    在實(shí)踐中了解Java反射機(jī)制應(yīng)用

    當(dāng)程序運(yùn)行時(shí),允許改變程序結(jié)構(gòu)或變量類型,這種語(yǔ)言稱為動(dòng)態(tài)語(yǔ)言。我們認(rèn)為java并不是動(dòng)態(tài)語(yǔ)言,但是它卻有一個(gè)非常突出的動(dòng)態(tài)相關(guān)機(jī)制,俗稱:反射。下面我們來簡(jiǎn)單學(xué)習(xí)一下吧
    2019-05-05
  • 淺析JAVA中的內(nèi)存結(jié)構(gòu)、重載、this與繼承

    淺析JAVA中的內(nèi)存結(jié)構(gòu)、重載、this與繼承

    這篇文章主要介紹了 JAVA中的內(nèi)存結(jié)構(gòu)、重載、this與繼承的相關(guān)資料,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-03-03
  • java時(shí)間 java.util.Calendar深入分析

    java時(shí)間 java.util.Calendar深入分析

    這篇文章主要介紹了java時(shí)間 java.util.Calendar深入分析的相關(guān)資料,需要的朋友可以參考下
    2017-02-02
  • Java刪除String中指定字符的11種方法匯總

    Java刪除String中指定字符的11種方法匯總

    這篇文章主要給大家介紹了關(guān)于Java刪除String中指定字符的11種方法,在Java中String類提供了許多方法來處理字符串,其中包括刪除指定字符的方法,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-11-11
  • MyBatisX插件之domain文件生成不了問題

    MyBatisX插件之domain文件生成不了問題

    文章描述了在使用MyBatisX插件生成MyBatis的domain文件時(shí)遇到的問題,特別是在使用MyBatisX版本1.6.1和MySQL版本8.0.34的情況下,生成的domain文件不完整,作者通過勾選Model選項(xiàng)解決了這個(gè)問題,并分享了這一經(jīng)驗(yàn),希望能幫助其他遇到類似問題的用戶
    2025-01-01
  • 基于java下載中g(shù)etContentLength()一直為-1的一些思路

    基于java下載中g(shù)etContentLength()一直為-1的一些思路

    下面小編就為大家?guī)硪黄趈ava下載中g(shù)etContentLength()一直為-1的一些思路。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-06-06
  • Java編寫簡(jiǎn)單計(jì)算器的完整實(shí)現(xiàn)過程

    Java編寫簡(jiǎn)單計(jì)算器的完整實(shí)現(xiàn)過程

    這篇文章主要給大家介紹了關(guān)于Java編寫簡(jiǎn)單計(jì)算器的完整實(shí)現(xiàn)過程,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • java數(shù)組的初始化及操作詳解

    java數(shù)組的初始化及操作詳解

    在本文中小編給大家整理了關(guān)于java數(shù)組的初始化及操作的相關(guān)知識(shí)點(diǎn)內(nèi)容,需要的讀者們參考下。
    2019-07-07
  • 最新評(píng)論

    修水县| 谢通门县| 焦作市| 蓝田县| 长岭县| 南木林县| 治多县| 永济市| 拉萨市| 通渭县| 富川| 河西区| 虹口区| 新平| 定日县| 和平县| 枣强县| 郁南县| 高邮市| 静安区| 本溪| 铅山县| 阿图什市| 平乡县| 栾川县| 靖西县| 南雄市| 建始县| 中宁县| 岚皋县| 嵊泗县| 武宣县| 翁源县| 眉山市| 德安县| 宜阳县| 财经| 故城县| 伊金霍洛旗| 泰和县| 凤阳县|