MyBatis事務(wù)原理與實(shí)戰(zhàn)深入解析
MyBatis 事務(wù)深度解析:原理、配置與企業(yè)級(jí)實(shí)戰(zhàn)
事務(wù)是保證數(shù)據(jù)一致性的核心機(jī)制,尤其在多步數(shù)據(jù)庫(kù)操作場(chǎng)景中(如 “下單減庫(kù)存”“轉(zhuǎn)賬轉(zhuǎn)賬”),事務(wù)的 ACID 特性(原子性、一致性、隔離性、持久性)能避免出現(xiàn)數(shù)據(jù)臟讀、幻讀、部分成功等問(wèn)題。MyBatis 作為持久層框架,本身不直接管理事務(wù),而是依賴底層數(shù)據(jù)源(如 JDBC)或整合 Spring 框架實(shí)現(xiàn)事務(wù)控制。本文將從事務(wù)核心概念出發(fā),深入拆解 MyBatis 事務(wù)的實(shí)現(xiàn)原理、兩種核心使用方式(原生 JDBC 事務(wù)、Spring 聲明式事務(wù))、隔離級(jí)別配置及企業(yè)級(jí)實(shí)戰(zhàn)場(chǎng)景,幫助開發(fā)者徹底掌握 MyBatis 事務(wù)的正確用法。
一、核心基礎(chǔ):MyBatis 事務(wù)的本質(zhì)與依賴
1. 事務(wù)的核心價(jià)值
在無(wú)事務(wù)控制的場(chǎng)景中,多步數(shù)據(jù)庫(kù)操作可能出現(xiàn) “部分成功” 的風(fēng)險(xiǎn)。例如 “用戶下單” 流程需執(zhí)行兩步操作:① 插入訂單記錄;② 扣減商品庫(kù)存。若第一步成功、第二步失敗,會(huì)導(dǎo)致 “訂單已創(chuàng)建但庫(kù)存未扣減” 的臟數(shù)據(jù)。事務(wù)的核心價(jià)值就是通過(guò) ACID 特性保證:多步操作 “要么全成功,要么全回滾”,確保數(shù)據(jù)一致性。
2. MyBatis 事務(wù)的底層依賴
MyBatis 本身不提供事務(wù)管理器,事務(wù)控制依賴以下兩種底層機(jī)制,核心是通過(guò)SqlSession控制數(shù)據(jù)庫(kù)連接的事務(wù)行為:
- JDBC 事務(wù):依賴 JDBC 的
Connection對(duì)象,通過(guò)setAutoCommit(false)關(guān)閉自動(dòng)提交,commit()提交事務(wù),rollback()回滾事務(wù),適用于非 Spring 環(huán)境; - Spring 事務(wù):Spring 提供統(tǒng)一的事務(wù)管理器(
DataSourceTransactionManager),MyBatis 通過(guò)SqlSessionFactory與 Spring 事務(wù)管理器整合,支持聲明式事務(wù)(@Transactional注解),是企業(yè)級(jí)開發(fā)的主流方案。
3. MyBatis 事務(wù)的核心組件
- SqlSession:MyBatis 的核心會(huì)話對(duì)象,每個(gè) SqlSession 綁定一個(gè)數(shù)據(jù)庫(kù)連接(
Connection),事務(wù)的提交 / 回滾本質(zhì)是通過(guò) SqlSession 控制 Connection 的事務(wù)行為; - TransactionFactory:事務(wù)工廠,負(fù)責(zé)創(chuàng)建
Transaction對(duì)象,默認(rèn)提供JdbcTransactionFactory(適配 JDBC 事務(wù))和ManagedTransactionFactory(適配容器管理事務(wù)); - Transaction:事務(wù)接口,封裝了事務(wù)的提交、回滾、關(guān)閉等操作,底層委托給 Connection 實(shí)現(xiàn);
- Executor:MyBatis 的執(zhí)行器,所有數(shù)據(jù)庫(kù)操作通過(guò) Executor 執(zhí)行,Executor 會(huì)通過(guò) Transaction 獲取數(shù)據(jù)庫(kù)連接,確保同一事務(wù)內(nèi)的操作使用同一個(gè) Connection。
二、原生 JDBC 事務(wù):MyBatis 手動(dòng)控制事務(wù)(非 Spring 環(huán)境)
在不使用 Spring 框架的場(chǎng)景中,MyBatis 通過(guò)原生 JDBC 事務(wù)實(shí)現(xiàn)手動(dòng)控制,核心是通過(guò)SqlSession的commit()和rollback()方法管理事務(wù),底層依賴 JDBC 的 Connection 對(duì)象。
1. 核心原理
- MyBatis 默認(rèn)開啟 “自動(dòng)提交事務(wù)”(
autoCommit=true),即每個(gè) SQL 語(yǔ)句獨(dú)立成為一個(gè)事務(wù),執(zhí)行后自動(dòng)提交; - 手動(dòng)控制事務(wù)時(shí),需先通過(guò)
sqlSessionFactory.openSession(false)關(guān)閉自動(dòng)提交,此時(shí) SqlSession 綁定的 Connection 處于 “事務(wù)未提交” 狀態(tài); - 多步 SQL 操作執(zhí)行完成后,調(diào)用
sqlSession.commit()提交事務(wù);若執(zhí)行過(guò)程中拋出異常,調(diào)用sqlSession.rollback()回滾事務(wù); - 事務(wù)提交 / 回滾后,需關(guān)閉 SqlSession 釋放連接。
2. 實(shí)戰(zhàn)演示:原生 JDBC 事務(wù)手動(dòng)控制
(1)環(huán)境準(zhǔn)備(非 Spring)
- 依賴配置(pom.xml):
<!-- MyBatis核心依賴 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.13</version>
</dependency>
<!-- MySQL驅(qū)動(dòng) -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.33</version>
</dependency>
<!-- 數(shù)據(jù)源(C3P0) -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.5</version>
</dependency>- MyBatis 配置文件(mybatis-config.xml):
<configuration>
<!-- 環(huán)境配置:配置事務(wù)工廠和數(shù)據(jù)源 -->
<environments default="development">
<environment id="development">
<!-- 事務(wù)工廠:使用JDBC事務(wù)工廠 -->
<transactionManager type="JDBC"/>
<!-- 數(shù)據(jù)源:C3P0連接池 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test_mybatis?useSSL=false&serverTimezone=Asia/Shanghai"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
<property name="poolMaximumActiveConnections" value="10"/>
</dataSource>
</environment>
</environments>
<!-- 映射器掃描 -->
<mappers>
<mapper resource="mapper/OrderMapper.xml"/>
<mapper resource="mapper/ProductMapper.xml"/>
</mappers>
</configuration>(2)Mapper 接口與 XML(下單減庫(kù)存場(chǎng)景)
- OrderMapper.java(插入訂單):
public interface OrderMapper {
int insertOrder(Order order);
}
- ProductMapper.java(扣減庫(kù)存):
public interface ProductMapper {
int decreaseStock(@Param("productId") Long productId, @Param("num") Integer num);
}
- OrderMapper.xml:
<mapper namespace="com.example.mapper.OrderMapper">
<insert id="insertOrder" parameterType="com.example.entity.Order">
INSERT INTO `order`(order_no, product_id, num, create_time)
VALUES(#{orderNo}, #{productId}, #{num}, NOW())
</insert>
</mapper>- ProductMapper.xml:
<mapper namespace="com.example.mapper.ProductMapper">
<update id="decreaseStock">
UPDATE product SET stock = stock - #{num} WHERE id = #{productId} AND stock >= #{num}
</update>
</mapper>(3)手動(dòng)控制事務(wù)代碼
public class TransactionDemo {
public static void main(String[] args) {
// 1. 加載MyBatis配置,創(chuàng)建SqlSessionFactory
String resource = "mybatis-config.xml";
try (InputStream inputStream = Resources.getResourceAsStream(resource)) {
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2. 開啟SqlSession,關(guān)閉自動(dòng)提交(false表示手動(dòng)控制事務(wù))
SqlSession sqlSession = sqlSessionFactory.openSession(false);
try {
// 3. 獲取Mapper接口
OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
ProductMapper productMapper = sqlSession.getMapper(ProductMapper.class);
// 4. 模擬下單流程:① 插入訂單;② 扣減庫(kù)存
Order order = new Order();
order.setOrderNo(UUID.randomUUID().toString());
order.setProductId(1L);
order.setNum(2);
orderMapper.insertOrder(order); // 第一步:插入訂單
int rows = productMapper.decreaseStock(1L, 2); // 第二步:扣減庫(kù)存
if (rows == 0) {
throw new RuntimeException("庫(kù)存不足,扣減失敗");
}
// 5. 所有操作成功,提交事務(wù)
sqlSession.commit();
System.out.println("事務(wù)提交成功:下單流程完成");
} catch (Exception e) {
// 6. 發(fā)生異常,回滾事務(wù)
sqlSession.rollback();
System.out.println("事務(wù)回滾:" + e.getMessage());
} finally {
// 7. 關(guān)閉SqlSession,釋放連接
sqlSession.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}3. 核心注意事項(xiàng)
- 必須通過(guò)
openSession(false)關(guān)閉自動(dòng)提交,否則事務(wù)控制失效; - 同一事務(wù)內(nèi)的所有操作必須使用同一個(gè) SqlSession(確保使用同一個(gè)數(shù)據(jù)庫(kù)連接);
- 異常捕獲后必須手動(dòng)調(diào)用
rollback(),否則事務(wù)會(huì)一直處于未提交狀態(tài),導(dǎo)致連接泄露; - 事務(wù)提交 / 回滾后,SqlSession 不可重復(fù)使用,需重新創(chuàng)建。
三、Spring 聲明式事務(wù):MyBatis 企業(yè)級(jí)主流方案
在 Spring 框架中,MyBatis 與 Spring 事務(wù)管理器深度整合,支持聲明式事務(wù)(通過(guò)@Transactional注解),無(wú)需手動(dòng)控制SqlSession的提交 / 回滾,簡(jiǎn)化事務(wù)代碼,是企業(yè)級(jí)開發(fā)的首選方案。
1. 核心原理
- Spring 提供
DataSourceTransactionManager作為事務(wù)管理器,該管理器通過(guò) MyBatis 的SqlSessionFactory獲取數(shù)據(jù)庫(kù)連接,統(tǒng)一管理事務(wù); - 當(dāng)方法添加
@Transactional注解后,Spring 會(huì)通過(guò) AOP 動(dòng)態(tài)生成代理對(duì)象,在方法執(zhí)行前開啟事務(wù)(關(guān)閉 Connection 自動(dòng)提交),方法執(zhí)行成功后提交事務(wù),執(zhí)行失?。⊕伋霎惓#┖蠡貪L事務(wù); - Spring 事務(wù)管理器與 MyBatis 的
SqlSession無(wú)縫協(xié)同:同一事務(wù)內(nèi),Spring 會(huì)確保所有 MyBatis 操作使用同一個(gè)SqlSession(綁定同一個(gè) Connection),保證事務(wù)原子性。
2. 實(shí)戰(zhàn)演示:Spring 聲明式事務(wù)整合 MyBatis
(1)環(huán)境準(zhǔn)備(Spring Boot + MyBatis)
- 依賴配置(pom.xml):
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.10</version>
</parent>
<dependencies>
<!-- Spring Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- MyBatis + Spring Boot整合依賴 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.3.1</version>
</dependency>
<!-- MySQL驅(qū)動(dòng) -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>- 配置文件(application.yml):
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/test_mybatis?useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: 123456
# Spring事務(wù)配置(可選,默認(rèn)已配置DataSourceTransactionManager)
transaction:
rollback-on-commit-failure: true # 提交失敗時(shí)回滾
mybatis:
mapper-locations: classpath:mapper/**/*.xml
type-aliases-package: com.example.entity
configuration:
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印SQL,便于調(diào)試(2)Service 層添加 @Transactional 注解
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private ProductMapper productMapper;
/**
* 下單流程:插入訂單 + 扣減庫(kù)存
* @Transactional:聲明式事務(wù),默認(rèn) RuntimeException 觸發(fā)回滾
*/
@Transactional(
rollbackFor = Exception.class, // 所有異常都回滾(默認(rèn)僅RuntimeException回滾)
propagation = Propagation.REQUIRED, // 事務(wù)傳播行為:默認(rèn),當(dāng)前無(wú)事務(wù)則創(chuàng)建新事務(wù)
isolation = Isolation.DEFAULT // 隔離級(jí)別:默認(rèn),使用數(shù)據(jù)庫(kù)默認(rèn)隔離級(jí)別
)
public void createOrder(Order order) {
// 1. 插入訂單
orderMapper.insertOrder(order);
// 2. 扣減庫(kù)存
int rows = productMapper.decreaseStock(order.getProductId(), order.getNum());
if (rows == 0) {
throw new RuntimeException("庫(kù)存不足,下單失敗");
}
// 3. 模擬其他業(yè)務(wù)操作(如記錄日志)
System.out.println("下單成功,訂單號(hào):" + order.getOrderNo());
}
}(3)Controller 層測(cè)試
@RestController
@RequestMapping("/api/orders")
public class OrderController {
@Autowired
private OrderService orderService;
@PostMapping
public ResponseEntity<String> createOrder(@RequestBody Order order) {
try {
order.setOrderNo(UUID.randomUUID().toString());
orderService.createOrder(order);
return ResponseEntity.ok("下單成功");
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("下單失敗:" + e.getMessage());
}
}
}3. @Transactional 注解核心配置參數(shù)
@Transactional注解提供豐富的配置參數(shù),可根據(jù)業(yè)務(wù)需求調(diào)整事務(wù)行為,核心參數(shù)如下:
| 參數(shù)名 | 作用說(shuō)明 | 可選值 |
|---|---|---|
rollbackFor | 指定觸發(fā)回滾的異常類型(默認(rèn)僅 RuntimeException 及其子類回滾) | 如Exception.class(所有異?;貪L)、SQLException.class(特定異?;貪L) |
noRollbackFor | 指定不觸發(fā)回滾的異常類型 | 如BusinessException.class(業(yè)務(wù)異常不回滾) |
propagation | 事務(wù)傳播行為(多事務(wù)方法嵌套時(shí)的行為) | REQUIRED(默認(rèn))、SUPPORTS、REQUIRES_NEW、NESTED 等 |
isolation | 事務(wù)隔離級(jí)別(解決臟讀、不可重復(fù)讀、幻讀問(wèn)題) | DEFAULT(默認(rèn),數(shù)據(jù)庫(kù)隔離級(jí)別)、READ_UNCOMMITTED、READ_COMMITTED 等 |
timeout | 事務(wù)超時(shí)時(shí)間(秒),超過(guò)時(shí)間未完成則自動(dòng)回滾 | 如30(30 秒超時(shí)) |
readOnly | 是否為只讀事務(wù)(僅查詢操作,設(shè)置為 true 可優(yōu)化性能,不可執(zhí)行增刪改) | true/false(默認(rèn) false) |
關(guān)鍵參數(shù)詳解:
- 事務(wù)傳播行為:最常用
REQUIRED(當(dāng)前無(wú)事務(wù)則創(chuàng)建新事務(wù),有事務(wù)則加入當(dāng)前事務(wù))和REQUIRES_NEW(無(wú)論當(dāng)前是否有事務(wù),都創(chuàng)建新事務(wù)); - 事務(wù)隔離級(jí)別:企業(yè)級(jí)常用
READ_COMMITTED(避免臟讀,大多數(shù)數(shù)據(jù)庫(kù)默認(rèn)級(jí)別),SERIALIZABLE(最高隔離級(jí)別,避免所有并發(fā)問(wèn)題,但性能最低); - readOnly:純查詢方法建議設(shè)置
readOnly=true,Spring 會(huì)優(yōu)化事務(wù)配置(如關(guān)閉寫操作權(quán)限),提升查詢性能。
四、MyBatis 事務(wù)常見問(wèn)題與解決方案
1. 事務(wù)不生效問(wèn)題(高頻問(wèn)題)
問(wèn)題現(xiàn)象:
@Transactional注解添加后,事務(wù)未生效(部分操作成功、部分失敗時(shí)未回滾)。
常見原因與解決方案:
- 原因 1:方法非 public 修飾:Spring AOP 僅對(duì) public 方法生成代理,非 public 方法的
@Transactional注解無(wú)效;解決方案:確保事務(wù)方法為 public 修飾; - 原因 2:異常被 catch 捕獲未拋出:Spring 事務(wù)僅在方法拋出指定異常時(shí)才回滾,若異常被 try-catch 捕獲且未重新拋出,事務(wù)不會(huì)回滾;解決方案:捕獲異常后手動(dòng)拋出(如
throw new RuntimeException(e)),或使用TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()手動(dòng)觸發(fā)回滾; - 原因 3:數(shù)據(jù)源未被 Spring 管理:MyBatis 的 SqlSessionFactory 未使用 Spring 的數(shù)據(jù)源,導(dǎo)致 Spring 事務(wù)管理器無(wú)法控制連接;解決方案:確保數(shù)據(jù)源通過(guò)
spring.datasource配置,由 Spring 自動(dòng)注入; - 原因 4:內(nèi)部方法調(diào)用:同一類中無(wú)事務(wù)方法調(diào)用有事務(wù)方法,AOP 無(wú)法攔截,事務(wù)無(wú)效;解決方案:將事務(wù)方法抽取到其他 Service 類,或通過(guò)
AopContext.currentProxy()獲取代理對(duì)象調(diào)用。
2. 事務(wù)并發(fā)問(wèn)題(臟讀、不可重復(fù)讀、幻讀)
問(wèn)題說(shuō)明:
多線程并發(fā)操作同一數(shù)據(jù)時(shí),可能出現(xiàn)以下問(wèn)題:
- 臟讀:一個(gè)事務(wù)讀取到另一個(gè)事務(wù)未提交的數(shù)據(jù);
- 不可重復(fù)讀:同一事務(wù)內(nèi)多次查詢同一數(shù)據(jù),結(jié)果不一致;
- 幻讀:同一事務(wù)內(nèi)多次查詢,結(jié)果集行數(shù)不一致。
解決方案:
- 調(diào)整事務(wù)隔離級(jí)別:如設(shè)置
isolation = Isolation.READ_COMMITTED(避免臟讀)、Isolation.REPEATABLE_READ(避免臟讀和不可重復(fù)讀); - 加鎖:通過(guò)數(shù)據(jù)庫(kù)鎖(如行鎖、表鎖)或分布式鎖(Redis/ZooKeeper)控制并發(fā)訪問(wèn);
- 避免長(zhǎng)事務(wù):長(zhǎng)事務(wù)會(huì)占用數(shù)據(jù)庫(kù)連接,增加并發(fā)沖突概率,盡量拆分長(zhǎng)事務(wù)為短事務(wù)。
3. 事務(wù)提交失敗問(wèn)題
問(wèn)題現(xiàn)象:
方法執(zhí)行無(wú)異常,但事務(wù)提交失敗(數(shù)據(jù)未入庫(kù))。
常見原因與解決方案:
- 原因 1:數(shù)據(jù)庫(kù)引擎不支持事務(wù):如 MySQL 的 MyISAM 引擎不支持事務(wù),InnoDB 引擎支持;解決方案:將數(shù)據(jù)庫(kù)表引擎改為 InnoDB;
- 原因 2:事務(wù)超時(shí):事務(wù)執(zhí)行時(shí)間超過(guò)
timeout配置,被 Spring 自動(dòng)回滾;解決方案:優(yōu)化 SQL 執(zhí)行效率,或適當(dāng)增大timeout值; - 原因 3:連接池參數(shù)不合理:連接池最大連接數(shù)不足,導(dǎo)致事務(wù)無(wú)法獲取連接提交;解決方案:調(diào)整連接池參數(shù)(如
spring.datasource.hikari.max-active)。
五、企業(yè)級(jí)實(shí)戰(zhàn):MyBatis 事務(wù)最佳實(shí)踐
1. 分層事務(wù)控制原則
- 事務(wù)應(yīng)添加在 Service 層:Service 層負(fù)責(zé)業(yè)務(wù)邏輯整合,多步數(shù)據(jù)庫(kù)操作的事務(wù)控制應(yīng)在 Service 層統(tǒng)一管理,避免在 Controller 或 Mapper 層添加事務(wù);
- 粒度適中:事務(wù)粒度不宜過(guò)大(避免長(zhǎng)事務(wù)),也不宜過(guò)?。ū苊馐聞?wù)碎片化),以 “一個(gè)完整業(yè)務(wù)場(chǎng)景” 為單位(如 “下單”“轉(zhuǎn)賬”)。
2. 高頻場(chǎng)景事務(wù)配置示例
(1)純查詢方法(只讀事務(wù))
// 純查詢方法,設(shè)置readOnly=true優(yōu)化性能
@Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
public List<Order> getOrderByUserId(Long userId) {
return orderMapper.selectByUserId(userId);
}(2)轉(zhuǎn)賬業(yè)務(wù)(高一致性要求)
// 轉(zhuǎn)賬業(yè)務(wù):扣減付款方余額 + 增加收款方余額,要求強(qiáng)一致性
@Transactional(
rollbackFor = Exception.class,
isolation = Isolation.READ_COMMITTED,
timeout = 30
)
public void transfer(Long fromUserId, Long toUserId, BigDecimal amount) {
// 扣減付款方余額
userAccountMapper.decreaseBalance(fromUserId, amount);
// 增加收款方余額
userAccountMapper.increaseBalance(toUserId, amount);
}(3)嵌套事務(wù)(REQUIRES_NEW)
// 主事務(wù):創(chuàng)建訂單
@Transactional(rollbackFor = Exception.class)
public void createOrder(Order order) {
orderMapper.insertOrder(order);
// 調(diào)用子事務(wù)方法(創(chuàng)建訂單日志,獨(dú)立事務(wù),即使失敗不影響主事務(wù))
logService.recordOrderLog(order.getId());
}
// 子事務(wù):記錄訂單日志(獨(dú)立事務(wù))
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
public void recordOrderLog(Long orderId) {
OrderLog log = new OrderLog();
log.setOrderId(orderId);
log.setOperateTime(LocalDateTime.now());
orderLogMapper.insert(log);
}3. 事務(wù)監(jiān)控與排查技巧
- 開啟 Spring 事務(wù)日志:在 application.yml 中配置
logging.level.org.springframework.transaction=DEBUG,可查看事務(wù)開啟、提交、回滾的詳細(xì)日志; - 打印 SQL 執(zhí)行日志:MyBatis 配置
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl,查看 SQL 執(zhí)行順序和參數(shù); - 數(shù)據(jù)庫(kù)事務(wù)日志:如 MySQL 的 binlog 日志,可排查事務(wù)提交是否寫入數(shù)據(jù)庫(kù)。
六、總結(jié)
MyBatis 事務(wù)的核心是 “通過(guò) SqlSession 控制數(shù)據(jù)庫(kù)連接的事務(wù)行為”,底層依賴 JDBC 事務(wù)機(jī)制,企業(yè)級(jí)開發(fā)中主要與 Spring 聲明式事務(wù)整合,通過(guò)@Transactional注解簡(jiǎn)化事務(wù)控制。掌握 MyBatis 事務(wù)的關(guān)鍵在于:
- 理解事務(wù)的 ACID 特性,明確事務(wù)的適用場(chǎng)景(多步數(shù)據(jù)庫(kù)操作需保證一致性);
- 區(qū)分原生 JDBC 事務(wù)和 Spring 聲明式事務(wù)的使用場(chǎng)景(非 Spring 環(huán)境用原生,Spring 環(huán)境用聲明式);
- 熟練配置
@Transactional注解的核心參數(shù)(尤其是rollbackFor、propagation、isolation); - 規(guī)避常見問(wèn)題(如事務(wù)不生效、并發(fā)沖突、提交失敗),遵循分層事務(wù)控制原則。
在實(shí)際開發(fā)中,應(yīng)根據(jù)業(yè)務(wù)場(chǎng)景選擇合適的事務(wù)策略:簡(jiǎn)單場(chǎng)景用 Spring 默認(rèn)配置,高一致性場(chǎng)景調(diào)整隔離級(jí)別和傳播行為,并發(fā)場(chǎng)景結(jié)合鎖機(jī)制,確保數(shù)據(jù)一致性和系統(tǒng)性能的平衡。
到此這篇關(guān)于MyBatis事務(wù)原理與實(shí)戰(zhàn)深入解析的文章就介紹到這了,更多相關(guān)MyBatis事務(wù)原理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- MyBatisPlus+Spring實(shí)現(xiàn)聲明式事務(wù)的方法實(shí)現(xiàn)
- Atomikos + MybatisPlus解決多數(shù)據(jù)源事務(wù)一致性問(wèn)題解決
- MyBatisPlus中事務(wù)處理的實(shí)現(xiàn)
- Mybatis事務(wù)如何跟Spring結(jié)合(數(shù)據(jù)庫(kù)事務(wù)特性和Spring事務(wù)管理源碼)
- 一文搞懂?MyBatis的事務(wù)管理機(jī)制
- mysql+mybatis實(shí)現(xiàn)存儲(chǔ)過(guò)程+事務(wù)?+?多并發(fā)流水號(hào)獲取
- MyBatis事務(wù)管理模塊詳解
相關(guān)文章
SpringBoot時(shí)間格式化的方法小結(jié)
SpringBoot中的時(shí)間格式化通常指的是將Java中的日期時(shí)間類型轉(zhuǎn)換為指定格式的字符串,或者將字符串類型的時(shí)間解析為Java中的日期時(shí)間類型,本文小編將給大家詳細(xì)總結(jié)了SpringBoot時(shí)間格式化的方法,剛興趣的小伙伴跟著小編一起來(lái)看看吧2023-10-10
SpringBoot應(yīng)用jar包啟動(dòng)原理詳解
本文主要介紹了SpringBoot應(yīng)用jar包啟動(dòng)原理詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-03-03
@ControllerAdvice之全局異常處理過(guò)程
文章介紹了在Java中處理異常的兩種方式:就地解決和向上拋出,并重點(diǎn)介紹了Spring框架中的@ControllerAdvice注解,用于實(shí)現(xiàn)全局異常處理,從而避免了在每個(gè)Controller類中重復(fù)編寫try-catch代碼塊,這種方法不僅提高了代碼的可維護(hù)性,還使得異常處理邏輯的修改更加方便2025-11-11
實(shí)例解析使用Java實(shí)現(xiàn)基本的音頻播放器的編寫要點(diǎn)
這篇文章主要介紹了使用Java實(shí)現(xiàn)基本的音頻播放器的代碼要點(diǎn)實(shí)例分享,包括音頻文件的循環(huán)播放等功能實(shí)現(xiàn)的關(guān)鍵點(diǎn),需要的朋友可以參考下2016-01-01
MyBatis學(xué)習(xí)教程(三)-MyBatis配置優(yōu)化
這篇文章主要介紹了MyBatis學(xué)習(xí)教程(三)-MyBatis配置優(yōu)化的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-05-05
SpringBoot項(xiàng)目整合OpenFeign啟動(dòng)失敗及運(yùn)行時(shí)常見錯(cuò)誤解決方案
文章總結(jié)了在使用Feign進(jìn)行服務(wù)調(diào)用時(shí)可能遇到的常見問(wèn)題及其解決方案,涵蓋了依賴配置、接口定義、運(yùn)行時(shí)錯(cuò)誤和其它常見問(wèn)題的解決方法,建議使用兼容的版本、統(tǒng)一的包名結(jié)構(gòu),并為接口方法添加HTTP注解,感興趣的朋友跟隨小編一起看看吧2026-01-01
Linux下Java Python啟動(dòng)管理腳本方便程序管理
這篇文章主要為大家介紹了Linux下Java/Python啟動(dòng)管理腳本方便程序管理,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11

