首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

SpringMVC + MyBatis 聲明式事務管理實戰:配置陷阱與 MySQL 引擎踩坑記

     編輯:Java 相關知識

前言

聲明式事務是 Spring 核心優勢之一,但在 SpringMVC + MyBatis 整合中,掃描順序衝突與數據庫引擎不支援事務是兩大高頻踩坑點。本文記錄完整配置流程與核心問題排查。

一、配置文件分層與掃描隔離(關鍵)

Spring 容器啟動順序:web.xml → root-context.xml(業務層) → servlet-context.xml(Web 層)。

核心原則:root-context 掃描 Service/DAO,排除 Controller;servlet-context 掃描 Controller,排除 Service。否則 Controller 會注入未經事務增強的原始 Service。

1.1 root-context.xml(業務層容器)

<!-- 掃描 Service、DAO、Component,排除 Controller -->
<context:component-scan base-package="com.sence">
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-scan>

<!-- 數據源配置 -->
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
    <property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
    <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=UTC" />
    <property name="username" value="root" />
    <property name="password" value="123456" />
</bean>

<!-- MyBatis SqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="mapperLocations" value="classpath:mapper/**/*.xml" />
    <property name="typeAliasesPackage" value="com.sence.entity" />
</bean>

<!-- Mapper 掃描 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="com.sence.dao" />
    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
</bean>

1.2 servlet-context.xml(Web 層容器)

<!-- 僅掃描 Controller -->
<context:component-scan base-package="com.sence">
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service" />
</context:component-scan>

<!-- MVC 基礎配置 -->
<mvc:annotation-driven />
<mvc:default-servlet-handler />

二、聲明式事務配置(基於 AOP)

<!-- 事務管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
</bean>

<!-- 切點:Service 實現類所有方法 -->
<aop:config>
    <aop:pointcut id="serviceMethods" expression="execution(* com.sence.service.impl.*.*(..))" />
    <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethods" />
</aop:config>

<!-- 事務屬性定義 -->
<tx:advice id="txAdvice" transaction-manager="txManager">
    <tx:attributes>
        <!-- 查詢方法只讀優化 -->
        <tx:method name="find*" read-only="true" />
        <tx:method name="get*" read-only="true" />
        <tx:method name="select*" read-only="true" />
        <tx:method name="query*" read-only="true" />
        <!-- 寫操作:遇到自定義異常回滾 -->
        <tx:method name="save*" rollback-for="BizException" />
        <tx:method name="insert*" rollback-for="BizException" />
        <tx:method name="update*" rollback-for="BizException" />
        <tx:method name="delete*" rollback-for="BizException" />
        <!-- 默認:運行時異常回滾 -->
        <tx:method name="*" rollback-for="java.lang.RuntimeException" />
    </tx:attributes>
</tx:advice>

三、核心踩坑:事務不回滾排查全記錄

3.1 現象

Service 方法拋出 BizException,日誌顯示進入 doRollback(),但數據庫數據未回滾。

3.2 排查路徑

  1. 切點表達式:確認 execution(* com.sence.service.impl.*.*(..)) 匹配目標類
  2. 掃描隔離:確認 Controller 未在 root-context 掃描,Service 未在 servlet-context 掃描
  3. 異常類型:rollback-for 指定的異常是否為拋出異常的父類
  4. 事務傳播:是否誤用 PROPAGATION_NEVER 或 NOT_SUPPORTED
  5. 數據庫引擎:最終兇手——表引擎為 MyISAM,不支援事務!

3.3 解決方案

-- 檢查表引擎
SHOW CREATE TABLE `order`;

-- 修改為 InnoDB
ALTER TABLE `order` ENGINE=InnoDB;

-- 或建表時指定
CREATE TABLE `order` (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    ...
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

四、MySQL 事務支援對照表

存儲引擎事務支援行級鎖外鍵適用場景
InnoDB✅ ACID✅✅核心業務表、高併發寫入
MyISAM❌❌(表鎖)❌只讀/日誌/統計表
Memory❌❌❌臨時緩存表

五、進階優化建議

  1. 異常體系設計:業務異常繼承 RuntimeException,系統異常繼承 Exception,明確 rollback-for 策略
  2. 只讀事務優化:查詢方法標註 read-only="true",MyBatis 可跳過脏檢查,數據庫可優化快照讀
  3. 事務超時:<tx:method name="*" timeout="30" /> 防止長事務持有鎖
  4. 隔離級別:高併發場景考慮 READ_COMMITTED + 行鎖,避免間隙鎖死鎖
  5. 編程式事務備選:複雜業務邏輯可用 TransactionTemplate 精確控制邊界

六、總結

聲明式事務配置三部曲:掃描隔離正確 → AOP 切點精準 → 底層引擎支援。特別注意:MySQL 表必須使用 InnoDB 引擎,這是事務生效的物理基礎。建立「配置-代碼-數據庫」三層排查思維,可快速定位事務失效根因。

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