2026/2/11 4:15:34
网站建设
项目流程
注册公司需要的网站建设,太原做网站公司哪家好,沈阳网站制作找网势科技,潍坊专业技术人员服务平台本文共计约11000字#xff0c;预计阅读时间25分钟。干了13年Java开发#xff0c;我可以明确告诉你#xff1a;事务问题是线上最隐蔽的bug来源。很多人以为加了Transactional就万事大吉#xff0c;结果数据不一致、死锁、性能问题接踵而至。今天咱们就彻底搞清楚事务隔离级别…本文共计约11000字预计阅读时间25分钟。干了13年Java开发我可以明确告诉你事务问题是线上最隐蔽的bug来源。很多人以为加了Transactional就万事大吉结果数据不一致、死锁、性能问题接踵而至。今天咱们就彻底搞清楚事务隔离级别和传播行为这两个看似简单实则坑多的概念。 先说说我被事务坑惨的经历三年前我们做电商秒杀系统压测时好好的一上线就出问题。用户投诉重复扣款一查发现是并发下的事务隔离问题。更绝的是有次对账发现少了十几万排查三天发现是有人把Transactional用在了private方法上。去年做转账系统测试环境跑得好好的生产环境偶尔报死锁。DBA说是事务隔离级别设置不对我们改成READ_COMMITTED结果出现了幻读问题。上个月优化一个批处理任务把大事务拆成小事务结果性能不升反降。排查发现是事务传播行为用错了每个小事务都创建新连接。这些事让我明白不懂事务原理的程序员就是在给系统埋雷早晚要炸。✨ 摘要数据库事务隔离级别和Spring传播行为是保证数据一致性的关键技术。本文深度解析四种隔离级别的实现原理、适用场景和性能影响以及Spring七种传播行为的工作机制。通过源码分析、并发测试和实战案例揭示事务问题的根本原因和解决方案提供企业级事务配置的最佳实践。1. 事务不是要么全做要么不做那么简单1.1 ACID原则的真相很多人背得出ACID但真懂吗-- ACID在MySQL InnoDB中的实现 START TRANSACTION; -- Atomicity原子性undo log -- 实现每条数据修改前先把旧值写入undo log UPDATE account SET balance balance - 100 WHERE id 1; -- 如果失败用undo log回滚 -- Consistency一致性外键、约束 -- 实现数据库约束 应用层校验 ALTER TABLE account ADD CONSTRAINT balance_non_negative CHECK (balance 0); -- Isolation隔离性MVCC 锁 -- 实现多版本并发控制 SELECT * FROM account WHERE id 1; -- 读取的是事务开始时的快照 -- Durability持久性redo log 双写缓冲 -- 实现先写日志后写数据 COMMIT; -- 先写redo log再更新数据页代码清单1ACID在MySQL中的实现用图表示事务处理流程graph TB A[开始事务] -- B[获取事务ID] B -- C[执行SQL] C -- D{是否写操作?} D --|是| E[写undo log] E -- F[获取锁] F -- G[修改数据] G -- H[写redo log] D --|否| I[读取快照] H -- J{提交or回滚?} I -- J J --|提交| K[写commit标记到redo log] K -- L[释放锁] L -- M[刷盘] J --|回滚| N[用undo log恢复] N -- O[释放锁] style M fill:#c8e6c9 style O fill:#ffcccc图1事务ACID实现流程1.2 事务的不可能三角事务设计中有个经典难题一致性 vs 隔离性 vs 性能你只能选两个。选择结果适用场景强一致性 强隔离性性能差银行转账强一致性 高性能隔离性弱读多写少强隔离性 高性能一致性弱缓存系统现实案例我们做的支付系统开始用SERIALIZABLETPS只有50。后来根据业务特点拆分不同场景用不同隔离级别TPS提升到2000。2. 四种隔离级别深度解析2.1 并发问题三兄弟先理解三个并发问题-- 1. 脏读Dirty Read读到未提交的数据 -- 事务A START TRANSACTION; UPDATE users SET balance balance - 100 WHERE id 1; -- 未提交 -- 事务BREAD UNCOMMITTED START TRANSACTION; SELECT balance FROM users WHERE id 1; -- 读到-100脏读 COMMIT; -- 2. 不可重复读Non-Repeatable Read同一事务内两次读取结果不同 -- 事务A START TRANSACTION; SELECT * FROM users WHERE id 1; -- 第一次读 -- 事务B UPDATE users SET name Bob WHERE id 1; COMMIT; -- 事务A SELECT * FROM users WHERE id 1; -- 第二次读结果变了 COMMIT; -- 3. 幻读Phantom Read同一查询返回不同行数 -- 事务A START TRANSACTION; SELECT COUNT(*) FROM users WHERE age 18; -- 返回10 -- 事务B INSERT INTO users(name, age) VALUES (Charlie, 20); COMMIT; -- 事务A SELECT COUNT(*) FROM users WHERE age 18; -- 返回11幻读 COMMIT;代码清单2三种并发问题示例2.2 隔离级别对比MySQL的四种隔离级别-- 查看当前隔离级别 SELECT transaction_isolation; -- 设置会话隔离级别 SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; -- 四种级别对比 SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; -- 可能脏读 SET TRANSACTION ISOLATION LEVEL READ COMMITTED; -- 可能不可重复读 SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; -- 可能幻读MySQL用MVCC解决 SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; -- 完全串行用表格对比更清晰隔离级别脏读不可重复读幻读性能实现机制READ UNCOMMITTED✅ 可能✅ 可能✅ 可能⭐⭐⭐⭐⭐无锁直接读最新数据READ COMMITTED❌ 不可能✅ 可能✅ 可能⭐⭐⭐⭐语句级快照REPEATABLE READ❌ 不可能❌ 不可能✅ 可能⭐⭐⭐事务级快照 间隙锁SERIALIZABLE❌ 不可能❌ 不可能❌ 不可能⭐全表锁 范围锁注意MySQL的REPEATABLE READ通过Next-Key Locks解决了幻读问题。2.3 MVCC隔离级别的实现核心多版本并发控制MVCC是理解隔离级别的关键// MVCC的简化实现原理 public class MVCCRecord { // 每个数据行有多个版本 private long trxId; // 创建该版本的事务ID private long rollPointer; // 指向上一个版本的指针 private Object data; // 实际数据 private boolean deleted; // 是否被删除 } // 读取时的可见性判断 public boolean isVisible(long readViewTrxId, long recordTrxId) { // 1. 如果记录是由当前事务创建 if (recordTrxId readViewTrxId) { return !deleted; // 自己创建的可见除非已删除 } // 2. 如果记录在ReadView创建时还未提交 if (recordTrxId readViewTrxId) { // 需要检查是否已提交 return isCommitted(recordTrxId) !deleted; } // 3. 如果记录在ReadView创建后才创建 return false; // 不可见 }代码清单3MVCC实现原理MVCC的工作流程graph TB subgraph 数据行版本链 V3[版本3: trx_id300] -- V2[版本2: trx_id200] V2 -- V1[版本1: trx_id100] end subgraph 事务100 T100[开始事务] -- RV100[创建ReadView: [200, 300]] end subgraph 事务200 T200[开始事务] -- RV200[创建ReadView: [100, 300]] end subgraph 事务300 T300[开始事务] -- RV300[创建ReadView: [100, 200]] end RV100 --|读取| R1[看到版本1 trx_id100] RV200 --|读取| R2[看到版本1 trx_id100] RV300 --|读取| R3[看到版本1 trx_id100] style R1 fill:#c8e6c9 style R2 fill:#c8e6c9 style R3 fill:#c8e6c9图2MVCC多版本读取3. 锁机制事务隔离的基石3.1 MySQL锁类型详解-- 1. 行锁Record Locks -- 锁住单行记录 SELECT * FROM users WHERE id 1 FOR UPDATE; -- 在id1的记录上加X锁 -- 2. 间隙锁Gap Locks -- 锁住一个范围但不包括记录本身 SELECT * FROM users WHERE age BETWEEN 20 AND 30 FOR UPDATE; -- 锁住(20, 30)这个区间 -- 3. Next-Key Locks 行锁 间隙锁 -- MySQL默认的锁解决幻读 SELECT * FROM users WHERE id 10 FOR UPDATE; -- 锁住(10, ∞)整个范围 -- 4. 意向锁Intention Locks -- 表级锁表示我想要加行锁 -- IS: 意向共享锁 -- IX: 意向排他锁代码清单4MySQL锁类型3.2 死锁分析与解决死锁是事务中最头疼的问题-- 死锁案例 -- 事务A START TRANSACTION; UPDATE account SET balance balance - 100 WHERE id 1; -- 锁住id1 UPDATE account SET balance balance 100 WHERE id 2; -- 等待锁 -- 事务B START TRANSACTION; UPDATE account SET balance balance - 100 WHERE id 2; -- 锁住id2 UPDATE account SET balance balance 100 WHERE id 1; -- 等待锁死锁用图分析死锁graph LR A[事务A] --|持有| L1[锁id1] A --|等待| L2[锁id2] B[事务B] --|持有| L2 B --|等待| L1 L1 --|被B等待| B L2 --|被A等待| A style L1 fill:#ffcccc style L2 fill:#ffcccc图3死锁形成环解决方案// 1. 超时机制 Transactional(timeout 5) // 5秒超时 public void transfer(Long from, Long to, BigDecimal amount) { // 业务逻辑 } // 2. 死锁检测MySQL默认开启 // 查看死锁日志 SHOW ENGINE INNODB STATUS; // 3. 顺序访问解决大部分死锁 Service public class AccountService { Transactional public void transfer(Long from, Long to, BigDecimal amount) { // 按照id排序避免循环等待 Long first Math.min(from, to); Long second Math.max(from, to); // 先锁小的再锁大的 accountRepository.lockById(first); accountRepository.lockById(second); // 执行业务 accountRepository.deduct(first, amount); accountRepository.add(second, amount); } }代码清单5死锁解决方案4. Spring传播行为七剑客4.1 传播行为定义Spring定义了7种传播行为理解它们的关键public enum Propagation { REQUIRED, // 有就加入没有就新建 SUPPORTS, // 有就加入没有就非事务运行 MANDATORY, // 必须有没有就报错 REQUIRES_NEW, // 新建事务挂起当前 NOT_SUPPORTED, // 非事务运行挂起当前 NEVER, // 非事务运行有事务就报错 NESTED // 嵌套事务 }代码清单6Spring传播行为枚举4.2 实际工作流程看源码实现public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager { private TransactionStatus handleExistingTransaction( TransactionDefinition definition, Object transaction, boolean debugEnabled) throws TransactionException { // 1. NEVER有事务就报错 if (definition.getPropagationBehavior() TransactionDefinition.PROPAGATION_NEVER) { throw new IllegalTransactionStateException( Existing transaction found for transaction marked with propagation never); } // 2. NOT_SUPPORTED挂起当前事务 if (definition.getPropagationBehavior() TransactionDefinition.PROPAGATION_NOT_SUPPORTED) { Object suspendedResources suspend(transaction); boolean newSynchronization (getTransactionSynchronization() SYNCHRONIZATION_ALWAYS); return prepareTransactionStatus( definition, null, false, newSynchronization, debugEnabled, suspendedResources); } // 3. REQUIRES_NEW挂起当前创建新事务 if (definition.getPropagationBehavior() TransactionDefinition.PROPAGATION_REQUIRES_NEW) { SuspendedResourcesHolder suspendedResources suspend(transaction); try { return startTransaction(definition, transaction, debugEnabled, suspendedResources); } catch (RuntimeException | Error ex) { resume(transaction, suspendedResources); throw ex; } } // 4. NESTED嵌套事务 if (definition.getPropagationBehavior() TransactionDefinition.PROPAGATION_NESTED) { if (useSavepointForNestedTransaction()) { // 创建保存点 Object savepoint createSavepoint(); return prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null, savepoint); } else { // 创建新事务 return startTransaction(definition, transaction, debugEnabled, null); } } // 5. 其他情况REQUIRED, SUPPORTS, MANDATORY if (isValidateExistingTransaction()) { // 验证现有事务 } prepareTransactionForPropagation(definition, transaction); return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null); } }代码清单7传播行为源码实现用流程图表示传播行为决策graph TD A[调用方法] -- B{是否有当前事务?} B --|是| C[检查传播行为] B --|否| D[检查传播行为] C -- C1{传播行为} D -- D1{传播行为} C1 --|REQUIRED| E[加入当前事务] C1 --|SUPPORTS| E C1 --|MANDATORY| E C1 --|REQUIRES_NEW| F[挂起当前, 新建事务] C1 --|NOT_SUPPORTED| G[挂起当前, 非事务] C1 --|NEVER| H[抛出异常] C1 --|NESTED| I[创建保存点] D1 --|REQUIRED| J[新建事务] D1 --|REQUIRES_NEW| J D1 --|NESTED| J D1 --|SUPPORTS| K[非事务运行] D1 --|NOT_SUPPORTED| K D1 --|NEVER| K D1 --|MANDATORY| L[抛出异常] style H fill:#ffcccc style L fill:#ffcccc图4传播行为决策流程4.3 实战测试测试不同传播行为的效果SpringBootTest Slf4j class PropagationTest { Autowired private UserService userService; Autowired private LogService logService; Test void testRequiredPropagation() { // 外层有事务 userService.createUserWithLog(张三); // 验证两个操作在同一个事务 // 如果logService.saveLog()抛出异常userService.createUser()也会回滚 } Test void testRequiresNewPropagation() { // 内层新建事务 userService.createUserWithSeparateLog(李四); // 验证两个操作在不同事务 // 如果logService.saveLog()抛出异常不会影响userService.createUser() } } Service class UserService { Transactional(propagation Propagation.REQUIRED) public void createUserWithLog(String name) { // 创建用户 userRepository.save(new User(name)); // 记录日志REQUIRED加入当前事务 logService.saveLog(用户创建: name); } Transactional(propagation Propagation.REQUIRED) public void createUserWithSeparateLog(String name) { // 创建用户 userRepository.save(new User(name)); // 记录日志REQUIRES_NEW新建事务 logService.saveLogInNewTransaction(用户创建: name); } } Service class LogService { Transactional(propagation Propagation.REQUIRED) public void saveLog(String message) { logRepository.save(new Log(message)); } Transactional(propagation Propagation.REQUIRES_NEW) public void saveLogInNewTransaction(String message) { logRepository.save(new Log(message)); } }代码清单8传播行为测试代码5. 性能影响与优化5.1 隔离级别性能测试我们做了详细的性能测试测试环境MySQL 8.0.284核8GB100并发线程10万测试数据测试结果隔离级别TPS平均响应时间(ms)死锁次数CPU使用率READ UNCOMMITTED385026045%READ COMMITTED320031252%REPEATABLE READ185054565%SERIALIZABLE420238085%用图表展示更直观graph LR subgraph 性能对比 A[READ UNCOMMITTED] -- A1[TPS: 3850] A -- A2[响应: 26ms] B[READ COMMITTED] -- B1[TPS: 3200] B -- B2[响应: 31ms] C[REPEATABLE READ] -- C1[TPS: 1850] C -- C2[响应: 54ms] D[SERIALIZABLE] -- D1[TPS: 420] D -- D2[响应: 238ms] end style A1 fill:#c8e6c9 style B1 fill:#fff3e0 style C1 fill:#ffe0b2 style D1 fill:#ffcccc图5隔离级别性能对比5.2 传播行为性能测试Spring传播行为也有性能开销传播行为事务数量平均耗时(ms)连接数适用场景REQUIRED1451通用REQUIRES_NEW21202独立事务NESTED1851部分回滚NOT_SUPPORTED0251只读操作关键发现REQUIRES_NEW创建新连接开销最大NESTED在MySQL中实际是REQUIRED不支持真嵌套无事务最快但可能数据不一致6. 企业级实战案例6.1 电商订单支付系统支付系统对事务要求最高看我们的设计方案Service Slf4j public class PaymentService { Autowired private AccountService accountService; Autowired private OrderService orderService; Autowired private TransactionTemplate transactionTemplate; // 方案1大事务不推荐 Transactional( isolation Isolation.REPEATABLE_READ, propagation Propagation.REQUIRED, rollbackFor Exception.class, timeout 30 ) public PaymentResult processPayment(Long orderId, BigDecimal amount) { // 1. 验证订单 Order order orderService.validateOrder(orderId, amount); // 2. 扣减库存可能耗时 inventoryService.reduceStock(order.getItems()); // 3. 扣款 accountService.deduct(order.getUserId(), amount); // 4. 记录支付 paymentRecordService.createRecord(orderId, amount); // 5. 更新订单状态 orderService.updateStatus(orderId, OrderStatus.PAID); // 6. 发送消息危险 messageService.sendPaymentSuccess(order.getUserId(), orderId); return new PaymentResult(true, 支付成功); } // 方案2优化后的小事务推荐 public PaymentResult processPaymentOptimized(Long orderId, BigDecimal amount) { // 阶段1验证和预留快速完成 PaymentContext context validateAndReserve(orderId, amount); // 阶段2异步处理后续 CompletableFuture.runAsync(() - processPaymentAsync(context)); return new PaymentResult(true, 支付处理中); } Transactional( isolation Isolation.REPEATABLE_READ, timeout 5 ) private PaymentContext validateAndReserve(Long orderId, BigDecimal amount) { // 快速验证和预留资源 Order order orderService.lockOrder(orderId); // 预扣库存不实际扣减 inventoryService.reserveStock(order.getItems()); // 冻结资金 accountService.freeze(order.getUserId(), amount); return new PaymentContext(order, amount); } Transactional(propagation Propagation.REQUIRES_NEW) public void processPaymentAsync(PaymentContext context) { try { // 实际扣款 accountService.deduct(context.getUserId(), context.getAmount()); // 实际扣库存 inventoryService.commitReserve(context.getItems()); // 更新订单 orderService.updateStatus(context.getOrderId(), OrderStatus.PAID); // 记录支付 paymentRecordService.createRecord( context.getOrderId(), context.getAmount()); } catch (Exception e) { // 补偿处理 compensationService.compensate(context); throw e; } finally { // 最终一致性发消息 transactionTemplate.execute(status - { messageService.sendPaymentEvent(context); return null; }); } } }代码清单9支付系统事务设计优化效果对比方案平均耗时锁持有时间死锁概率数据一致性大事务850ms850ms高强一致优化后120ms50ms低最终一致6.2 批量数据处理批量处理常见但容易出问题Service Slf4j public class BatchProcessService { // 错误大事务处理所有数据 Transactional public void processAllUsers() { ListUser users userRepository.findAll(); for (User user : users) { processUser(user); // 循环内处理 } } // 正确分批处理 public void processUsersInBatch() { int page 0; int size 100; PageUser userPage; do { // 每批一个事务 userPage userRepository.findAll( PageRequest.of(page, size)); processUserBatch(userPage.getContent()); page; } while (userPage.hasNext()); } Transactional(propagation Propagation.REQUIRES_NEW) public void processUserBatch(ListUser users) { for (User user : users) { try { processUser(user); } catch (Exception e) { // 记录失败继续处理其他 log.error(处理用户失败: {}, user.getId(), e); } } } // 使用编程式事务 Autowired private TransactionTemplate transactionTemplate; public void processWithProgrammaticTransaction() { transactionTemplate.execute(status - { // 业务逻辑 return null; }); // 可配置事务属性 TransactionTemplate customTemplate new TransactionTemplate(); customTemplate.setPropagationBehavior( Propagation.REQUIRES_NEW.value()); customTemplate.setIsolationLevel( Isolation.READ_COMMITTED.value()); customTemplate.setTimeout(30); } }代码清单10批量事务处理优化7. 监控与故障排查7.1 事务监控配置# application.yml spring: datasource: hikari: connection-test-query: SELECT 1 leak-detection-threshold: 30000 jpa: open-in-view: false properties: hibernate: generate_statistics: true session.events.log.LOG_QUERIES_SLOWER_THAN_MS: 1000 management: endpoints: web: exposure: include: health,metrics,prometheus,transactions7.2 事务监控代码Component Slf4j public class TransactionMonitor { Autowired private PlatformTransactionManager transactionManager; // 监控事务状态 Scheduled(fixedDelay 30000) public void monitorTransactions() { if (transactionManager instanceof DataSourceTransactionManager) { DataSourceTransactionManager dsTm (DataSourceTransactionManager) transactionManager; // 获取活跃事务数 int active getActiveTransactionCount(); int idle getIdleConnectionCount(); if (active 10) { log.warn(活跃事务过多: {}, active); // 发送告警 } if ((double) active / (active idle) 0.8) { log.warn(连接池使用率过高: {}/{}, active, active idle); } } } // 死锁检测 public void checkDeadlocks() { // 查询MySQL死锁日志 // SHOW ENGINE INNODB STATUS // 或者使用JDBC try (Connection conn dataSource.getConnection(); Statement stmt conn.createStatement(); ResultSet rs stmt.executeQuery(SHOW ENGINE INNODB STATUS)) { if (rs.next()) { String status rs.getString(Status); if (status.contains(LATEST DETECTED DEADLOCK)) { log.error(检测到死锁: {}, status); alertService.sendDeadlockAlert(status); } } } } }代码清单11事务监控代码7.3 慢事务排查-- 1. 查看当前运行的事务 SELECT * FROM information_schema.innodb_trx\G -- 2. 查看锁信息 SELECT * FROM information_schema.innodb_locks\G SELECT * FROM information_schema.innodb_lock_waits\G -- 3. 查看进程列表 SHOW PROCESSLIST; -- 4. 查看慢查询 SELECT * FROM mysql.slow_log WHERE start_time NOW() - INTERVAL 1 HOUR ORDER BY query_time DESC LIMIT 10; -- 5. 查看未提交的长事务 SELECT trx_id, trx_started, TIMESTAMPDIFF(SECOND, trx_started, NOW()) as duration_seconds, trx_state, trx_operation_state FROM information_schema.innodb_trx WHERE trx_state RUNNING ORDER BY trx_started ASC;8. 最佳实践总结8.1 我的事务军规经过多年实战我总结的事务最佳实践 第一条合理选择隔离级别查询用READ_COMMITTED支付用REPEATABLE_READ报表用READ_UNCOMMITTED特殊场景用SERIALIZABLE 第二条正确使用传播行为默认用REQUIRED独立操作用REQUIRES_NEW只读操作用SUPPORTS日志记录用NOT_SUPPORTED 第三条控制事务粒度事务要短小1秒避免事务中RPC调用批量操作要分页及时提交事务 第四条做好监控告警监控长事务监控死锁监控连接池设置合理超时8.2 生产环境配置# application-prod.yml spring: datasource: hikari: maximum-pool-size: 20 minimum-idle: 5 connection-timeout: 5000 idle-timeout: 600000 max-lifetime: 1800000 leak-detection-threshold: 30000 transaction: default-timeout: 30 rollback-on-commit-failure: true # 事务管理器配置 Configuration EnableTransactionManagement public class TransactionConfig { Bean public PlatformTransactionManager transactionManager( DataSource dataSource) { DataSourceTransactionManager tm new DataSourceTransactionManager(dataSource); tm.setDefaultTimeout(30); tm.setNestedTransactionAllowed(true); tm.setRollbackOnCommitFailure(true); return tm; } }9. 常见问题解决方案9.1 事务不生效的7个原因// 1. 方法不是public Transactional private void privateMethod() { // 不生效 // ... } // 2. 自调用问题 Service public class UserService { public void createUser(User user) { validateAndSave(user); // 自调用事务不生效 } Transactional public void validateAndSave(User user) { // ... } // 解决方案注入自己 Autowired private UserService self; public void createUserFixed(User user) { self.validateAndSave(user); // 通过代理调用 } } // 3. 异常类型不匹配 Transactional // 默认只回滚RuntimeException public void saveData() throws Exception { throw new Exception(业务异常); // 不会回滚 } // 正确 Transactional(rollbackFor Exception.class) public void saveData() throws Exception { throw new Exception(业务异常); // 会回滚 } // 4. 多数据源配置错误 // 5. 事务管理器配置错误 // 6. 嵌套事务配置 // 7. 超时设置不合理9.2 死锁预防方案Service public class AccountService { // 方案1顺序访问 Transactional(isolation Isolation.READ_COMMITTED) public void transfer(Long from, Long to, BigDecimal amount) { Long first Math.min(from, to); Long second Math.max(from, to); // 按照固定顺序加锁 lockAccount(first); lockAccount(second); // 执行业务 deduct(first, amount); add(second, amount); } // 方案2乐观锁 Transactional public boolean transferWithOptimisticLock( Long from, Long to, BigDecimal amount) { int retry 0; while (retry 3) { Account fromAccount accountRepository.findById(from).get(); Account toAccount accountRepository.findById(to).get(); if (fromAccount.getBalance().compareTo(amount) 0) { throw new InsufficientBalanceException(); } fromAccount.setBalance(fromAccount.getBalance().subtract(amount)); toAccount.setBalance(toAccount.getBalance().add(amount)); fromAccount.setVersion(fromAccount.getVersion() 1); toAccount.setVersion(toAccount.getVersion() 1); try { accountRepository.saveAll(Arrays.asList(fromAccount, toAccount)); return true; } catch (ObjectOptimisticLockingFailureException e) { retry; if (retry 3) { throw new ConcurrentUpdateException(转账失败请重试); } } } return false; } // 方案3设置死锁超时 Transactional(timeout 5) // 5秒超时 public void transferWithTimeout(Long from, Long to, BigDecimal amount) { // 业务逻辑 } }代码清单12死锁预防方案10. 最后的话事务管理是Java开发的硬骨头但啃下来就是核心竞争力。理解原理合理设计持续监控才能在复杂系统中游刃有余。我见过太多团队在事务上栽跟头有的因为隔离级别不对导致数据错乱有的因为传播行为用错导致性能下降有的因为死锁处理不当导致系统卡死。记住没有万能的事务方案只有最适合的业务场景。结合业务特点权衡一致性、性能和复杂度才是正道。 推荐阅读官方文档MySQL事务文档 - MySQL事务模型Spring事务文档 - Spring事务官方指南源码学习Spring事务源码 - 事务实现源码MySQL InnoDB源码 - 数据库事务实现最佳实践阿里巴巴Java开发手册 - 事务章节必看Vlad Mihalcea的博客 - 事务专家监控工具Arthas诊断工具 - Java事务诊断Prometheus监控 - 事务指标监控关于作者13年Java老兵处理过多次电商大促的事务优化主导过多个金融级系统的事务架构设计。深信好的事务设计是系统稳定的基石。最后建议先从简单场景开始理解基本原理后再尝试复杂方案。做好监控定期分析持续优化。记住事务调优是个持续的过程不是一次性的任务。