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

MyBatis事務(wù)管理模塊詳解

 更新時(shí)間:2026年02月09日 10:41:46   作者:探索java  
本文主要介紹了MyBatis事務(wù)管理模塊詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

1 引言

在企業(yè)級應(yīng)用開發(fā)中,事務(wù)管理是保證數(shù)據(jù)一致性與完整性的核心機(jī)制。無論是銀行轉(zhuǎn)賬、訂單支付,還是庫存扣減,這些操作都需要保證要么全部成功,要么全部失敗,否則就會(huì)產(chǎn)生數(shù)據(jù)不一致的嚴(yán)重問題。

在 Java 生態(tài)中,MyBatis 作為一款輕量級 ORM 框架,因其靈活的 SQL 定制能力和較低的學(xué)習(xí)成本被廣泛應(yīng)用。然而,MyBatis 本身并不是一個(gè)“全棧”持久層框架,它并不直接管理數(shù)據(jù)源的生命周期,而是通過事務(wù)管理機(jī)制協(xié)調(diào) JDBC 連接的提交與回滾。

理解 MyBatis 的事務(wù)管理機(jī)制不僅有助于我們編寫正確、健壯的代碼,還能幫助我們在與 Spring 等框架整合時(shí),精準(zhǔn)定位事務(wù)相關(guān)問題(如事務(wù)未生效、連接泄漏、跨數(shù)據(jù)源事務(wù)失敗等)。

本系列文章的目標(biāo)是從概念、實(shí)現(xiàn)、源碼、整合、優(yōu)化五個(gè)維度,深入剖析 MyBatis 的事務(wù)管理機(jī)制,并給出實(shí)戰(zhàn)中的最佳實(shí)踐。

1.1 為什么事務(wù)管理如此重要

數(shù)據(jù)庫事務(wù)(Database Transaction)是保證ACID 特性(原子性 Atomicity、一致性 Consistency、隔離性 Isolation、持久性 Durability)的基礎(chǔ)。在分布式和高并發(fā)系統(tǒng)中,事務(wù)問題會(huì)被放大:

  • 原子性失效:轉(zhuǎn)賬扣款成功但入賬失敗,導(dǎo)致資金丟失。
  • 隔離性不足:并發(fā)讀寫導(dǎo)致臟讀、不可重復(fù)讀、幻讀。
  • 持久性丟失:系統(tǒng)崩潰后事務(wù)未持久化的數(shù)據(jù)丟失。

MyBatis 的事務(wù)管理器相當(dāng)于一個(gè)交通指揮員,它決定何時(shí)讓 SQL 執(zhí)行、何時(shí)提交或回滾,保證數(shù)據(jù)的一致性與安全性。

1.2 本文的核心關(guān)注點(diǎn)

本博客將重點(diǎn)分析以下幾個(gè)方面:

  • MyBatis 核心事務(wù)接口與實(shí)現(xiàn)類:Transaction、TransactionFactory、JdbcTransaction、ManagedTransaction 等。
  • 兩種事務(wù)管理機(jī)制:JDBC 事務(wù)與 MANAGED 事務(wù)的差異與適用場景。
  • 與 Spring 的整合:@Transactional 注解、TransactionSynchronizationManager 的作用。
  • 源碼解析:通過調(diào)用鏈路、類圖和流程圖揭示 MyBatis 事務(wù)的底層實(shí)現(xiàn)邏輯。
  • 常見問題與解決方案:事務(wù)未生效、連接泄漏、多數(shù)據(jù)源事務(wù)。
  • 性能優(yōu)化與最佳實(shí)踐:事務(wù)粒度控制、連接復(fù)用、隔離級別調(diào)整。

2 核心概念

在深入源碼分析之前,我們需要先厘清 MyBatis 事務(wù)管理的幾個(gè)核心概念。這不僅包括數(shù)據(jù)庫層面的事務(wù)定義,還涉及 MyBatis 在架構(gòu)上對事務(wù)的抽象與實(shí)現(xiàn)。

2.1 事務(wù)的定義與特性

事務(wù)(Transaction)是數(shù)據(jù)庫操作的一個(gè)邏輯單元,由一組 SQL 語句組成。這些語句要么全部成功提交,要么全部回滾撤銷,確保數(shù)據(jù)的一致性。事務(wù)必須滿足 ACID 四大特性:

  • 原子性(Atomicity):事務(wù)中的所有操作要么全部成功,要么全部失敗回滾。
  • 一致性(Consistency):事務(wù)執(zhí)行前后,數(shù)據(jù)必須處于一致狀態(tài)。
  • 隔離性(Isolation):并發(fā)事務(wù)之間相互隔離,互不干擾。
  • 持久性(Durability):事務(wù)提交后,對數(shù)據(jù)的修改是永久性的。

2.2 MyBatis 中的事務(wù)抽象

MyBatis 將事務(wù)管理功能抽象為一個(gè)核心接口和若干實(shí)現(xiàn)類,主要包括:

  • Transaction 接口:定義了事務(wù)的基本操作方法,如 commit()rollback()close()、getConnection() 等。
  • TransactionFactory 接口:用于創(chuàng)建具體的 Transaction 實(shí)例,支持通過不同配置生成不同類型的事務(wù)管理器。
  • JdbcTransaction:基于 JDBC 原生 API 實(shí)現(xiàn)的事務(wù)管理器,直接調(diào)用 java.sql.Connectioncommit()rollback() 方法。
  • ManagedTransaction:受外部容器(如 JEE 容器、Spring)管理的事務(wù)管理器,不直接控制事務(wù)提交與回滾。
public interface Transaction {
    Connection getConnection() throws SQLException;
    void commit() throws SQLException;
    void rollback() throws SQLException;
    void close() throws SQLException;
    Integer getTimeout() throws SQLException;
}

上面的 Transaction 接口就是 MyBatis 的事務(wù)核心抽象,所有事務(wù)管理器都必須實(shí)現(xiàn)該接口,以統(tǒng)一事務(wù)操作方式。

2.3 MyBatis 中的事務(wù)邊界

在 MyBatis 中,事務(wù)邊界主要由 SqlSession 控制:

  • 開啟事務(wù):獲取 SqlSession 并連接數(shù)據(jù)庫。
  • 提交事務(wù):調(diào)用 sqlSession.commit()。
  • 回滾事務(wù):調(diào)用 sqlSession.rollback()。
  • 關(guān)閉事務(wù):調(diào)用 sqlSession.close(),釋放連接。

如果與 Spring 整合,事務(wù)邊界的控制權(quán)則由 Spring 的 PlatformTransactionManager 及其實(shí)現(xiàn)類(如 DataSourceTransactionManager)接管。

2.4 概念小結(jié)

從架構(gòu)設(shè)計(jì)來看,MyBatis 的事務(wù)管理分為三個(gè)層次:

  • 接口層:定義統(tǒng)一的事務(wù)操作標(biāo)準(zhǔn)(TransactionTransactionFactory)。
  • 實(shí)現(xiàn)層:提供不同類型事務(wù)的具體實(shí)現(xiàn)(JdbcTransaction、ManagedTransaction)。
  • 調(diào)用層:由 SqlSession 或 Spring 框架驅(qū)動(dòng)事務(wù)的開啟、提交、回滾與關(guān)閉。

3 MyBatis 事務(wù)管理機(jī)制

MyBatis 提供了兩種核心事務(wù)管理機(jī)制:JDBC 事務(wù)MANAGED 事務(wù)。它們的區(qū)別主要在于事務(wù)控制權(quán)的歸屬以及事務(wù)生命周期的管理方式。

3.1 JDBC 事務(wù)

JDBC 事務(wù) 是 MyBatis 默認(rèn)的事務(wù)管理方式,由 MyBatis 直接通過 JDBC API 控制事務(wù)的提交與回滾。

  • 實(shí)現(xiàn)類JdbcTransaction
  • 控制權(quán):MyBatis 內(nèi)部
  • 適用場景:獨(dú)立使用 MyBatis 或不依賴外部容器時(shí)。

工作機(jī)制

  • MyBatis 獲取連接后,會(huì)將 autoCommit 設(shè)置為 false。
  • 執(zhí)行 SQL 后,由調(diào)用方顯式觸發(fā) commit()rollback()。
  • 事務(wù)結(jié)束后釋放連接回連接池。

示例代碼:

Transaction tx = new JdbcTransaction(dataSource, level, false);
try (Connection conn = tx.getConnection()) {
    // 執(zhí)行 SQL
    tx.commit();
} catch (SQLException e) {
    tx.rollback();
} finally {
    tx.close();
}

優(yōu)點(diǎn):簡單直接。 缺點(diǎn):無法與外部事務(wù)資源(如 JTA)協(xié)作。

3.2 MANAGED 事務(wù)

MANAGED 事務(wù) 不直接控制事務(wù)提交與回滾,交由外部容器(如 Spring、JEE 容器)管理。

  • 實(shí)現(xiàn)類ManagedTransaction
  • 控制權(quán):外部容器
  • 適用場景:Spring 管理事務(wù)、JEE 容器環(huán)境。

工作機(jī)制

  • MyBatis 從外部容器獲取連接。
  • 不在 MyBatis 內(nèi)部執(zhí)行 commit()rollback()。
  • 可通過 closeConnection 配置決定是否由 MyBatis 關(guān)閉連接。

配置示例:

<transactionManager type="MANAGED">
    <property name="closeConnection" value="false"/>
</transactionManager>

3.3 配置對比

<!-- JDBC 事務(wù)配置 -->
<transactionManager type="JDBC"/>
 
<!-- MANAGED 事務(wù)配置 -->
<transactionManager type="MANAGED">
    <property name="closeConnection" value="false"/>
</transactionManager>

3.4 差異總結(jié)

對比項(xiàng)JDBC 事務(wù)MANAGED 事務(wù)
控制權(quán)MyBatis 內(nèi)部外部容器
提交/回滾MyBatis 調(diào)用 commit()/rollback()外部容器負(fù)責(zé)
連接關(guān)閉MyBatis 內(nèi)部可由外部容器
場景獨(dú)立 MyBatis 項(xiàng)目Spring、JEE 容器環(huán)境

4 MyBatis 與 Spring 的事務(wù)整合

在實(shí)際開發(fā)中,MyBatis 很少單獨(dú)使用,更多是在 Spring 或 Spring Boot 框架中與其他數(shù)據(jù)訪問技術(shù)(如 JPA、JDBC Template)共存。為了在多種數(shù)據(jù)訪問方式間實(shí)現(xiàn)統(tǒng)一的事務(wù)控制,Spring 接管了 MyBatis 的事務(wù)管理。

4.1 整合的核心思想

MyBatis 原本通過 Transaction 接口及其實(shí)現(xiàn)類(如 JdbcTransaction、ManagedTransaction)來管理事務(wù)。在與 Spring 整合后,事務(wù)的開啟、提交、回滾等生命周期由 Spring 的 PlatformTransactionManager(通常是 DataSourceTransactionManager)全權(quán)負(fù)責(zé)。

4.2 核心組件

  • SqlSessionFactoryBean:Spring 提供的工廠類,用于生成 SqlSessionFactory,并配置數(shù)據(jù)源、事務(wù)工廠等。
  • SpringManagedTransactionFactory:Spring 對 MyBatis 事務(wù)工廠的實(shí)現(xiàn),用于生成 SpringManagedTransaction,它會(huì)委托 Spring 管理事務(wù)。
  • TransactionSynchronizationManager:Spring 的事務(wù)同步管理器,用于將數(shù)據(jù)庫連接綁定到當(dāng)前線程,實(shí)現(xiàn)事務(wù)上下文的共享。

4.3 事務(wù)接管流程

  • 當(dāng)業(yè)務(wù)方法被 @Transactional 標(biāo)記時(shí),Spring 的事務(wù)攔截器(TransactionInterceptor)會(huì)啟動(dòng)事務(wù)(通過 PlatformTransactionManager)。
  • 事務(wù)啟動(dòng)時(shí),DataSourceTransactionManager 會(huì)從連接池獲取連接,并綁定到 TransactionSynchronizationManager。
  • 當(dāng) MyBatis 執(zhí)行 SQL 時(shí),通過 SpringManagedTransactionTransactionSynchronizationManager 獲取當(dāng)前線程綁定的連接,而不是自己創(chuàng)建連接。
  • 提交或回滾事務(wù)的時(shí)機(jī)由 Spring 控制,在方法執(zhí)行結(jié)束時(shí)統(tǒng)一處理。

流程圖示意:

@Transactional 方法調(diào)用
       ↓
TransactionInterceptor 攔截
       ↓
PlatformTransactionManager 啟動(dòng)事務(wù)
       ↓
綁定連接到 TransactionSynchronizationManager
       ↓
MyBatis 執(zhí)行 SQL(SpringManagedTransaction 獲取連接)
       ↓
方法結(jié)束,統(tǒng)一提交或回滾事務(wù)

4.4 配置示例(Spring Boot)

@Configuration
@MapperScan("com.example.mapper")
public class MyBatisConfig {
 
    @Bean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setDataSource(dataSource);
        factoryBean.setTransactionFactory(new SpringManagedTransactionFactory());
        return factoryBean.getObject();
    }
}

4.5 關(guān)鍵點(diǎn)總結(jié)

  • Spring 整合 MyBatis 時(shí),TransactionFactory 必須設(shè)置為 SpringManagedTransactionFactory。
  • 所有事務(wù)邊界(開始、提交、回滾)都由 Spring 控制。
  • MyBatis 在 Spring 環(huán)境下不會(huì)主動(dòng)關(guān)閉連接,而是由 Spring 在事務(wù)結(jié)束時(shí)統(tǒng)一管理。

5 MyBatis 事務(wù)管理源碼解析

本節(jié)從源碼角度系統(tǒng)拆解 MyBatis 事務(wù)管理的關(guān)鍵接口與實(shí)現(xiàn),并補(bǔ)充與 Spring 整合時(shí)的調(diào)用鏈路。示例以 MyBatis 3.x 與 mybatis-spring 2.x 為藍(lán)本,代碼片段做了少量刪減與注釋以便理解。

5.1 總覽:類關(guān)系與模塊邊界

從宏觀上看,事務(wù)相關(guān)模塊可以分為四層:

  • 接口抽象層Transaction、TransactionFactory
  • MyBatis 內(nèi)部實(shí)現(xiàn)層JdbcTransactionManagedTransaction、對應(yīng)的 JdbcTransactionFactory、ManagedTransactionFactory
  • 執(zhí)行器交互層ExecutorBaseExecutorSimpleExecutor 等)在執(zhí)行前后調(diào)用 commit/rollback/close
  • Spring 整合層SpringManagedTransaction、SqlSessionTemplate、SqlSessionUtils、DataSourceTransactionManager、TransactionSynchronizationManager

類圖(簡化版):

classDiagram
  interface Transaction {
    +getConnection() Connection
    +commit()
    +rollback()
    +close()
    +getTimeout() Integer
  }
  class TransactionFactory {
    <<interface>>
    +newTransaction(Connection)
    +newTransaction(DataSource, level, autoCommit)
  }
  class JdbcTransaction
  class ManagedTransaction
  class JdbcTransactionFactory
  class ManagedTransactionFactory
  class SpringManagedTransaction
 
  Transaction <|.. JdbcTransaction
  Transaction <|.. ManagedTransaction
  Transaction <|.. SpringManagedTransaction
  TransactionFactory <|.. JdbcTransactionFactory
  TransactionFactory <|.. ManagedTransactionFactory

5.2Transaction接口逐行解讀

public interface Transaction {
    Connection getConnection() throws SQLException;  // 懶加載或直接返回當(dāng)前連接
    void commit() throws SQLException;               // 提交當(dāng)前連接的事務(wù)
    void rollback() throws SQLException;             // 回滾當(dāng)前連接的事務(wù)
    void close() throws SQLException;                // 歸還連接或?qū)嶋H關(guān)閉
    Integer getTimeout() throws SQLException;        // 可選的事務(wù)超時(shí)
}

設(shè)計(jì)要點(diǎn):

  • 連接懶加載:MyBatis 常在首次需要時(shí)創(chuàng)建/獲取連接,減少無謂占用。
  • 統(tǒng)一生命周期:不關(guān)心連接來自何處(直連或容器),一律通過 Transaction 抽象進(jìn)行提交/回滾/關(guān)閉。

5.3JdbcTransaction源碼要點(diǎn)

JdbcTransaction 直接基于 DataSourceConnection 控制事務(wù):

public class JdbcTransaction implements Transaction {
  private final DataSource dataSource;
  private Connection connection;
  private final TransactionIsolationLevel level;
  private final boolean autoCommit;
 
  @Override
  public Connection getConnection() throws SQLException {
    if (connection == null) {
      connection = dataSource.getConnection();
      if (level != null) connection.setTransactionIsolation(level.getLevel());
      setDesiredAutoCommit(autoCommit);
    }
    return connection;
  }
 
  private void setDesiredAutoCommit(boolean desired) throws SQLException {
    if (connection.getAutoCommit() != desired) {
      connection.setAutoCommit(desired); // JDBC 事務(wù)關(guān)鍵:autoCommit=false 以啟用顯式提交
    }
  }
 
  @Override
  public void commit() throws SQLException {
    if (connection != null && !connection.getAutoCommit()) connection.commit();
  }
 
  @Override
  public void rollback() throws SQLException {
    if (connection != null && !connection.getAutoCommit()) connection.rollback();
  }
 
  @Override
  public void close() throws SQLException {
    if (connection != null) {
      resetAutoCommit(); // 歸還連接前恢復(fù)狀態(tài)(對連接池很重要)
      connection.close();
    }
  }
}

關(guān)鍵點(diǎn):

  • 隔離級別設(shè)置:僅在首次獲取連接時(shí)設(shè)置,避免重復(fù)調(diào)用帶來的開銷。
  • autoCommit 管控:通過 autoCommit=false 啟用顯式事務(wù)邊界。
  • 資源歸還close() 前恢復(fù) autoCommit,防止影響連接池中后續(xù)租戶。

示例:獨(dú)立 MyBatis(非 Spring)使用

SqlSessionFactory factory = ...;
try (SqlSession session = factory.openSession(false)) { // 關(guān)閉自動(dòng)提交
    UserMapper mapper = session.getMapper(UserMapper.class);
    mapper.insert(u1);
    mapper.insert(u2);
    session.commit();
} catch (Exception ex) {
    session.rollback();
}

5.4ManagedTransaction源碼要點(diǎn)

ManagedTransaction 交由外部容器管理提交與回滾:

public class ManagedTransaction implements Transaction {
  private final DataSource dataSource;
  private Connection connection;
  private final boolean closeConnection; // 是否在 close() 時(shí)關(guān)閉連接
 
  @Override
  public Connection getConnection() throws SQLException {
    if (connection == null) {
      connection = dataSource.getConnection(); // 來自容器/代理
    }
    return connection;
  }
 
  @Override public void commit() {}     // 空實(shí)現(xiàn),由外部容器負(fù)責(zé)
  @Override public void rollback() {}
  @Override public void close() throws SQLException {
    if (closeConnection && connection != null) connection.close();
  }
}

關(guān)鍵點(diǎn):

  • 不觸碰事務(wù)邊界commit/rollback 空實(shí)現(xiàn),避免與容器沖突。
  • 連接關(guān)閉策略:通過 closeConnection 決定是否交回容器或由容器統(tǒng)一回收。

5.5TransactionFactory與具體工廠

TransactionFactory 把選擇權(quán)在配置期就確定下來:

public interface TransactionFactory {
  default void setProperties(Properties props) {}
  Transaction newTransaction(Connection conn);
  Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, boolean autoCommit);
}

兩個(gè)常用實(shí)現(xiàn):

  • JdbcTransactionFactory:創(chuàng)建 JdbcTransaction
  • ManagedTransactionFactory:創(chuàng)建 ManagedTransaction

XML 配置示例:

<environments default="dev">
  <environment id="dev">
    <transactionManager type="JDBC"/>
    <dataSource type="POOLED">...</dataSource>
  </environment>
</environments>

5.6 執(zhí)行器如何驅(qū)動(dòng)事務(wù):BaseExecutor

MyBatis 的 Executor 負(fù)責(zé)發(fā)起 SQL 執(zhí)行,并在恰當(dāng)時(shí)機(jī)觸發(fā)事務(wù)提交/回滾/關(guān)閉:

public abstract class BaseExecutor implements Executor {
  protected final Transaction transaction;
 
  @Override
  public void commit(boolean required) throws SQLException {
    if (closed) throw new ExecutorException("Closed");
    clearLocalCache();
    if (required) {
      transaction.commit(); // 委托給 Transaction 實(shí)現(xiàn)
    }
  }
 
  @Override
  public void rollback(boolean required) throws SQLException {
    if (!closed) {
      clearLocalCache();
      if (required) {
        transaction.rollback();
      }
    }
  }
 
  @Override
  public void close(boolean forceRollback) {
    try {
      try {
        if (forceRollback) rollback(true);
      } finally {
        transaction.close();
      }
    } catch (SQLException e) { ... }
  }
}

要點(diǎn):

  • 職責(zé)單一:執(zhí)行器并不直接操作 Connection,一切通過 Transaction 完成,保證可替換性。
  • 緩存清理:提交/回滾前清空本地緩存,確保一致性。

5.7 與 Spring 整合的源碼鏈路

當(dāng)引入 mybatis-spring 后,調(diào)用鏈整合如下:

  • @Transactional → AOP 代理 → TransactionInterceptor
  • TransactionInterceptor 使用 PlatformTransactionManager(常見:DataSourceTransactionManager)開始事務(wù)
  • DataSourceTransactionManager 獲取連接并綁定TransactionSynchronizationManager(線程上下文)
  • MyBatis 側(cè):SqlSessionTemplateSqlSessionUtils.getSqlSession → 檢索/創(chuàng)建 SqlSession
  • SpringManagedTransaction 調(diào)用 DataSourceUtils.getConnection(dataSource) → 從 TransactionSynchronizationManager 取出線程綁定連接
  • 方法結(jié)束時(shí)由 Spring 統(tǒng)一提交/回滾,最后釋放/歸還連接

關(guān)鍵類片段:

// mybatis-spring: SpringManagedTransaction#getConnection
public Connection getConnection() throws SQLException {
  if (this.connection == null) {
    this.connection = DataSourceUtils.getConnection(this.dataSource);
  }
  return this.connection;
}
 
// Spring: DataSourceUtils.getConnection
public static Connection getConnection(DataSource ds) {
  ConnectionHolder holder = (ConnectionHolder)
      TransactionSynchronizationManager.getResource(ds);
  if (holder != null && holder.hasConnection()) {
    return holder.getConnection();
  }
  Connection con = ds.getConnection();
  // 如果處于事務(wù)中,包裝為 ConnectionHolder 并綁定到線程
  // ...
  return con;
}

SqlSession 獲取與釋放SqlSessionUtils):

public static SqlSession getSqlSession(SqlSessionFactory factory, ExecutorType type, PersistenceExceptionTranslator translator) {
  SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(factory);
  if (holder != null) {
    return holder.getSqlSession(); // 復(fù)用當(dāng)前事務(wù)內(nèi)的 SqlSession
  }
  SqlSession session = factory.openSession(type);
  // 如果存在事務(wù),則注冊同步器,在事務(wù)完成時(shí)關(guān)閉 SqlSession
  // TransactionSynchronizationManager.registerSynchronization(...)
  return session;
}

5.8 時(shí)序圖:@Transactional 方法的一次完整調(diào)用

sequenceDiagram
  participant C as Client
  participant S as @Transactional Service
  participant TI as TransactionInterceptor
  participant TM as DataSourceTransactionManager
  participant TSM as TransactionSynchronizationManager
  participant SUT as SqlSessionTemplate
  participant SMT as SpringManagedTransaction
  participant DS as DataSource/Pool
  participant DB as Database
 
  C->>S: 調(diào)用業(yè)務(wù)方法
  S->>TI: AOP 攔截
  TI->>TM: begin() 開啟事務(wù)
  TM->>DS: getConnection()
  DS-->>TM: Connection
  TM->>TSM: 綁定 ConnectionHolder
  TI->>S: 繼續(xù)執(zhí)行業(yè)務(wù)邏輯
  S->>SUT: 執(zhí)行 Mapper 方法
  SUT->>SMT: getConnection()
  SMT->>TSM: 查詢線程綁定 Connection
  TSM-->>SMT: 返回同一 Connection
  SMT->>DB: 執(zhí)行 SQL
  SUT-->>S: 返回結(jié)果
  S->>TI: 方法結(jié)束
  TI->>TM: commit()/rollback()
  TM->>TSM: 清理并釋放連接
  TM->>DS: 歸還連接到連接池

5.9 邊界條件與細(xì)節(jié)

  • 多數(shù)據(jù)源:Spring 以 DataSource 為 key 進(jìn)行資源綁定,若同一事務(wù)中使用多個(gè)數(shù)據(jù)源,會(huì)分別綁定多個(gè) ConnectionHolder。務(wù)必確保 Mapper 使用正確的數(shù)據(jù)源。
  • 超時(shí)控制Transaction.getTimeout() 可與 Spring 超時(shí)策略協(xié)同(如 @Transactional(timeout=...))。
  • 只讀事務(wù):Spring 在只讀場景可能降低隔離或優(yōu)化執(zhí)行計(jì)劃,但數(shù)據(jù)庫是否真正利用只讀標(biāo)志取決于驅(qū)動(dòng)/方言。
  • SqlSession 復(fù)用:在事務(wù)內(nèi),同一 SqlSessionFactory 對應(yīng)單個(gè) SqlSession,跨線程不共享。

5.10 調(diào)試與定位建議

打開日志

# MyBatis 執(zhí)行與 JDBC 交互
logging.level.org.apache.ibatis=DEBUG
logging.level.jdbc.sqlonly=DEBUG
 
# Spring 事務(wù)與同步
logging.level.org.springframework.jdbc.datasource=DEBUG
logging.level.org.springframework.transaction=DEBUG
logging.level.org.mybatis.spring=DEBUG

打印連接標(biāo)識:通過攔截器或日志模式打印 Connection#hashCode(),確認(rèn)同一事務(wù)內(nèi)是否為同一連接。

異常邊界:務(wù)必在 @Transactional 入口層拋出(或顯式標(biāo)注)需要回滾的異常類型,否則可能出現(xiàn)“方法拋異常但未回滾”的錯(cuò)覺。

6 MyBatis 事務(wù)管理常見問題與解決方案

在實(shí)際項(xiàng)目中,MyBatis 的事務(wù)管理并非總是“開箱即用”,很多問題往往與配置、整合方式、事務(wù)傳播等相關(guān)。下面我們列出常見問題、成因以及對應(yīng)解決方案。

6.1 事務(wù)未生效

問題現(xiàn)象@Transactional 注解標(biāo)記的方法中執(zhí)行多條 SQL,但數(shù)據(jù)庫最終只部分提交,或回滾未生效。

常見原因

  • 事務(wù)未被 Spring 管理:MyBatis 直接使用 SqlSessionFactory.openSession() 獲取會(huì)話,繞過了 Spring 事務(wù)管理器。
  • 方法調(diào)用未經(jīng)過代理:同類內(nèi)部方法調(diào)用不會(huì)觸發(fā) Spring AOP 攔截,事務(wù)邏輯失效。
  • 事務(wù)傳播行為不匹配:如外層事務(wù)為 REQUIRES_NEW,內(nèi)層事務(wù)的回滾不影響外層事務(wù)。

解決方案

  • 確保通過 Mapper 接口由 Spring 管理的 Bean 調(diào)用。
  • 檢查 @Transactional 注解位置,確保是 public 方法且通過代理調(diào)用。
  • 根據(jù)業(yè)務(wù)需求正確配置 propagation 屬性。

6.2 數(shù)據(jù)庫連接泄漏

問題現(xiàn)象:系統(tǒng)長時(shí)間運(yùn)行后,連接池中的連接耗盡,出現(xiàn) java.sql.SQLTransientConnectionException: HikariPool-1 - Connection is not available。

常見原因

  • 事務(wù)或會(huì)話未正常關(guān)閉,連接未釋放回連接池。
  • MANAGED 事務(wù)模式下 closeConnection 配置錯(cuò)誤。

解決方案

  • 確保 SqlSession 使用 try-with-resources 或在 finally 塊中關(guān)閉。
  • 使用 Spring 時(shí)推薦 SpringManagedTransaction 以自動(dòng)管理連接釋放。

6.3 多數(shù)據(jù)源事務(wù)問題

問題現(xiàn)象:跨多個(gè)數(shù)據(jù)源的操作無法在同一事務(wù)中提交或回滾。

常見原因

  • Spring 默認(rèn)的 DataSourceTransactionManager 只支持單數(shù)據(jù)源。
  • 不同數(shù)據(jù)源的連接未統(tǒng)一在同一事務(wù)上下文中。

解決方案

  • 使用 JtaTransactionManager 或第三方分布式事務(wù)框架(如 Seata、Atomikos)。
  • 對于強(qiáng)一致性要求不高的場景,可拆分為獨(dú)立事務(wù)處理。

6.4 嵌套事務(wù)與傳播行為異常

問題現(xiàn)象:方法調(diào)用鏈中,內(nèi)層事務(wù)的回滾影響了外層事務(wù),或者預(yù)期的獨(dú)立事務(wù)沒有生效。

常見原因

  • Spring 事務(wù)傳播屬性未按需求配置,如使用 REQUIRED 導(dǎo)致內(nèi)外事務(wù)合并。

解決方案

  • 使用 REQUIRES_NEW 保證內(nèi)層事務(wù)獨(dú)立執(zhí)行。

  • 使用 NESTED 在支持 Savepoint 的數(shù)據(jù)庫中實(shí)現(xiàn)部分回滾。

6.5 MyBatis 緩存與事務(wù)提交

問題現(xiàn)象:事務(wù)提交后,查詢結(jié)果仍是舊數(shù)據(jù)。

常見原因

  • MyBatis 一級緩存、二級緩存未在事務(wù)提交時(shí)刷新。

解決方案

  • 在事務(wù)提交后調(diào)用 sqlSession.clearCache() 刷新緩存。

  • 合理配置 flushCache 屬性確保更新語句刷新緩存。

到此這篇關(guān)于MyBatis事務(wù)管理模塊詳解的文章就介紹到這了,更多相關(guān)MyBatis事務(wù)管理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java數(shù)據(jù)結(jié)構(gòu)與算法之插入算法實(shí)現(xiàn)數(shù)值排序示例

    java數(shù)據(jù)結(jié)構(gòu)與算法之插入算法實(shí)現(xiàn)數(shù)值排序示例

    這篇文章主要介紹了java數(shù)據(jù)結(jié)構(gòu)與算法之插入算法實(shí)現(xiàn)數(shù)值排序的方法,結(jié)合簡單實(shí)例形式分析了插入算法的節(jié)點(diǎn)操作與排序相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2016-08-08
  • Java獲取當(dāng)前時(shí)間的時(shí)間戳(13位和10位)

    Java獲取當(dāng)前時(shí)間的時(shí)間戳(13位和10位)

    本文主要介紹了Java獲取當(dāng)前時(shí)間的時(shí)間戳(13位和10位),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • spring-logback引用外部文件實(shí)現(xiàn)方式

    spring-logback引用外部文件實(shí)現(xiàn)方式

    本文介紹了如何在Spring微服務(wù)開發(fā)中實(shí)現(xiàn)統(tǒng)一的日志配置,包括使用logback的繼承方式和spring-logback.xml配置,以及如何解決logback-include.xml文件在jar包中的位置問題,通過這種方式,可以在統(tǒng)一的日志格式和存儲(chǔ)方式下,給予服務(wù)一定程度的自主控制
    2025-11-11
  • 基于Ajax用戶名驗(yàn)證、服務(wù)條款加載、驗(yàn)證碼生成的實(shí)現(xiàn)方法

    基于Ajax用戶名驗(yàn)證、服務(wù)條款加載、驗(yàn)證碼生成的實(shí)現(xiàn)方法

    本篇文章對Ajax用戶名驗(yàn)證、服務(wù)條款加載、驗(yàn)證碼生成的實(shí)現(xiàn)方法,進(jìn)行了詳細(xì)的分析介紹。需要的朋友參考下
    2013-05-05
  • Java LinkedHashMap 底層實(shí)現(xiàn)原理分析

    Java LinkedHashMap 底層實(shí)現(xiàn)原理分析

    LinkedHashMap繼承自HashMap實(shí)現(xiàn)了Map接口?;緦?shí)現(xiàn)同HashMap一樣,不同之處在于LinkedHashMap保證了迭代的有序性。其內(nèi)部維護(hù)了一個(gè)雙向鏈表,解決了 HashMap不能隨時(shí)保持遍歷順序和插入順序一致的問題。
    2021-05-05
  • 如何兩步解決maven依賴導(dǎo)入失敗的問題

    如何兩步解決maven依賴導(dǎo)入失敗的問題

    這篇文章主要介紹了如何兩步解決maven依賴導(dǎo)入失敗的問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • SpringBoot實(shí)現(xiàn)對靜態(tài)資源的訪問權(quán)限控制的三種方案

    SpringBoot實(shí)現(xiàn)對靜態(tài)資源的訪問權(quán)限控制的三種方案

    在日常的 Spring Boot 開發(fā)中,我們通常會(huì)使用安全認(rèn)證、授權(quán)手段來保護(hù)后端的 RESTful API,確保只有認(rèn)證和授權(quán)的用戶才能訪問,所以本文就給大家介紹SpringBoot中如何實(shí)現(xiàn)對靜態(tài)資源的訪問權(quán)限控制,需要的朋友可以參考下
    2025-09-09
  • 解決SpringAop內(nèi)部調(diào)用時(shí)不經(jīng)過代理類的問題

    解決SpringAop內(nèi)部調(diào)用時(shí)不經(jīng)過代理類的問題

    這篇文章主要介紹了解決SpringAop內(nèi)部調(diào)用時(shí)不經(jīng)過代理類的問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • 在Java中讀取CSV文件的方式

    在Java中讀取CSV文件的方式

    在項(xiàng)目開發(fā)中我們經(jīng)常需要讀取csv的內(nèi)容的操作,讀取的邏輯并不復(fù)雜,下面這篇文章主要給大家介紹了關(guān)于在Java中讀取CSV文件的方式,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-06-06
  • 解決JdbcTemplate查詢時(shí)報(bào)錯(cuò)Incorrect column count: expected 1, actual 17問題

    解決JdbcTemplate查詢時(shí)報(bào)錯(cuò)Incorrect column count: ex

    文章描述了在使用JdbcTemplate執(zhí)行查詢時(shí)遇到的`IncorrectResultSetColumnCountException`錯(cuò)誤,原因是`queryForList`方法返回的是`List<Map<String, Object>>`類型,不能直接轉(zhuǎn)換成對象,解決方法是將代碼修改為適當(dāng)?shù)牟樵兎绞?以避免錯(cuò)誤
    2026-01-01

最新評論

宝应县| 德州市| 闽侯县| 开平市| 井陉县| 逊克县| 保靖县| 兴山县| 青岛市| 泰顺县| 化德县| 中西区| 哈尔滨市| 淮南市| 庆安县| 包头市| 商南县| 兰州市| 株洲市| 乌兰察布市| 扎兰屯市| 和田市| 桓台县| 革吉县| 安西县| 滨海县| 云南省| 蕲春县| 佛坪县| 铜梁县| 山东| 瑞昌市| 太保市| 济源市| 陇川县| 邢台市| 德安县| 孝昌县| 太白县| 宜丰县| 玉树县|