首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Spring3 + MyBatis + MySQL 事務不回滾:autocommit 兩級設置終極解決

     編輯:程式設計綜合問答

現象

配置 @Transactional(rollbackFor=Exception.class),MySQL 表引擎為 InnoDB,但異常拋出後數據未回滾。

根本原因

MySQL autocommit 有兩個作用域:

  • SESSION 級:當前連接生效,SET SESSION autocommit=0。
  • GLOBAL 級:新連接默認值,SET GLOBAL autocommit=0(需 SUPER 權限,重啟失效)。

連接池(Druid/HikariCP/DBCP)獲取連接時,若未顯式設置 autocommit=false,會使用數據庫默認值(通常為 ON)。Spring 的 DataSourceTransactionManager 在事務開始時會調用 connection.setAutoCommit(false),但若連接池預先開啟了自動提交,或連接被複用時狀態未重置,事務邊界可能失效。

完整解決方案

1. 連接池層面強制關閉自動提交(推薦)

<!-- Druid 示例 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
    <property name="url" value="jdbc:mysql://localhost:3306/db?useSSL=false" />
    <property name="username" value="root" />
    <property name="password" value="pwd" />
    <property name="defaultAutoCommit" value="false" /> <!-- 關鍵 -->
</bean>

2. MyBatis SqlSessionFactory 設置

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="configurationProperties">
        <props>
            <prop key="autoCommit">false</prop>
        </props>
    </property>
</bean>

3. 事務管理器配置

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />

4. 驗證方法

@Transactional(rollbackFor = Exception.class)
public void testRollback() {
    userDao.insert(new User("A"));
    int i = 1/0; // 拋出異常
    userDao.insert(new User("B"));
}
// 檢查數據庫:應 0 條記錄

避坑清單

  • 檢查是否誤用 @Transactional(readOnly=true) 導致不回滾。
  • 確認異常類型匹配 rollbackFor(默認僅 RuntimeException/Error)。
  • MySQL 版本 ≥ 5.5,表確實為 InnoDB (SHOW TABLE STATUS)。
  • 未在業務代碼中捕獲異常並吞噬(必須拋出給 Spring)。
  • 多數據源場景確保事務管理器綁定正確 DataSource。

總結

「同時設置 SESSION 與 GLOBAL autocommit=0」治標不治本。核心在於連接池獲取連接時默認 autocommit=false,配合 Spring 事務管理器正確切換狀態。設置 defaultAutoCommit=false 即可徹底解決。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved