🌈个人主页 :一条泥憨鱼 (欢迎各位大佬莅临)

前言:
“事务(Transaction)”是数据库开发里非常重要的知识。
简单来说:
事务就是“一组操作,要么全部成功,要么全部失败”。
它主要用于:
- 转账
- 下订单
- 库存扣减
- 支付系统
- 多表更新
这些场景都不能只执行一半,否则数据就会出错。
一、为什么需要事务?
先看一个经典案例:
银行转账
假设:
- 张三账户:1000 元
- 李四账户:1000 元
现在张三给李四转 200 元。
正常流程:
11. 张三 -200 22. 李四 +200 3
如果没有事务会发生什么?
假设:
1张三扣钱成功 2↓ 3程序突然崩溃 4↓ 5李四没收到钱 6
结果:
1张三:800 2李四:1000 3
钱凭空消失了,这就是严重的数据错误。
有事务之后
事务会保证:
1要么两步都成功 2要么两步都失败 3
这样数据永远正确。
二、事务的四大特性(ACID)
事务最核心,也是老生常谈的知识。
1. Atomicity(原子性)
原子性:
一个事务中的所有操作,要么全部完成,要么全部不完成。
比如:
1A扣钱 2B加钱 3
不能只完成一半。
2. Consistency(一致性)
事务执行前后:
数据必须保持正确状态。
例如:
1转账前总金额:2000 2转账后总金额:仍然2000 3
3. Isolation(隔离性)
多个事务之间:
彼此互不干扰。
比如:
1用户A正在修改数据 2用户B不能读到中间状态 3
4. Durability(持久性)
事务提交后:
数据永久保存。
即使数据库崩溃,数据也不会丢失。
三、MySQL 中事务的基本操作
MySQL 提供了事务控制语句。
1. 开启事务
1START TRANSACTION; 2
或者:
1BEGIN; 2
2. 提交事务
1COMMIT; 2
提交后:
1数据永久生效 2
3. 回滚事务
1ROLLBACK; 2
回滚后:
1撤销事务中的所有操作 2
四、事务代码示例
创建测试表
账户表
1CREATE TABLE account( 2 id INT PRIMARY KEY AUTO_INCREMENT, 3 name VARCHAR(20), 4 money DOUBLE 5); 6
插入数据
1INSERT INTO account VALUES(NULL,'张三',1000); 2INSERT INTO account VALUES(NULL,'李四',1000); 3
五、没有事务的问题
1UPDATE account SET money = money - 200 WHERE name='张三'; 2 3-- 程序崩溃 4 5UPDATE account SET money = money + 200 WHERE name='李四'; 6
这样会导致数据错误。
六、使用事务解决问题
1START TRANSACTION; 2 3UPDATE account SET money = money - 200 WHERE name='张三'; 4 5UPDATE account SET money = money + 200 WHERE name='李四'; 6 7COMMIT; 8
如果发生异常
1START TRANSACTION; 2 3UPDATE account SET money = money - 200 WHERE name='张三'; 4 5-- 出现错误 6 7ROLLBACK; 8
这样:
1张三不会扣钱 2
数据库恢复原状。
七、Java 中操作事务
JavaWeb 开发里最常见。
一般使用:
- JDBC
- MyBatis
- Spring
这里先讲 JDBC 原理。
八、JDBC 默认事务机制
JDBC 默认:
1自动提交事务 2
即:
1每执行一条SQL 2自动commit 3
所以:
1conn.setAutoCommit(false); 2
非常重要。
九、JDBC 事务完整代码
转账案例
1import java.sql.Connection; 2import java.sql.DriverManager; 3import java.sql.PreparedStatement; 4 5public class Demo { 6 7 public static void main(String[] args) { 8 9 Connection conn = null; 10 11 try { 12 13 // 获取连接 14 conn = DriverManager.getConnection( 15 "jdbc:mysql://localhost:3306/test", 16 "root", 17 "123456"); 18 19 // 关闭自动提交 20 conn.setAutoCommit(false); 21 22 // 张三减200 23 String sql1 = 24 "update account set money = money - 200 where name=?"; 25 26 PreparedStatement ps1 = 27 conn.prepareStatement(sql1); 28 29 ps1.setString(1, "张三"); 30 31 ps1.executeUpdate(); 32 33 // 模拟异常 34 int a = 1 / 0; 35 36 // 李四加200 37 String sql2 = 38 "update account set money = money + 200 where name=?"; 39 40 PreparedStatement ps2 = 41 conn.prepareStatement(sql2); 42 43 ps2.setString(1, "李四"); 44 45 ps2.executeUpdate(); 46 47 // 提交事务 48 conn.commit(); 49 50 System.out.println("转账成功"); 51 52 } catch (Exception e) { 53 54 try { 55 56 // 回滚事务 57 if(conn != null){ 58 conn.rollback(); 59 } 60 61 } catch (Exception ex) { 62 ex.printStackTrace(); 63 } 64 65 System.out.println("转账失败"); 66 67 } finally { 68 69 try { 70 71 if(conn != null){ 72 conn.close(); 73 } 74 75 } catch (Exception e) { 76 e.printStackTrace(); 77 } 78 } 79 } 80} 81
十、事务执行流程图
1开始事务 2 ↓ 3执行SQL1 4 ↓ 5执行SQL2 6 ↓ 7是否异常? 8 ↓ ↓ 9否 是 10 ↓ ↓ 11commit rollback 12
十一、事务隔离级别
多个用户同时操作数据库时:
会产生并发问题。
MySQL 提供了:
四种隔离级别
1. Read Uncommitted(读未提交)
最低级别。
问题:
1脏读 2
即:
读取到别人未提交的数据。
2. Read Committed(读已提交)
解决:
1脏读 2
Oracle 默认级别。
3. Repeatable Read(可重复读)
MySQL 默认级别。
解决:
1脏读 2不可重复读 3
4. Serializable(串行化)
最高级别。
事务串行执行。
最安全:
1性能最差 2
十二、并发问题详解
1. 脏读
事务A:
1修改余额但未提交 2
事务B:
1读取到了这个未提交的数据 2
如果A回滚:
1B读到的数据就是假的 2
2. 不可重复读
同一个事务:
1第一次读取:1000 2第二次读取:1200 3
数据不一致。
3. 幻读
事务A读取:
1共有5条数据 2
事务B插入一条数据,事务A再次读取:
1变成6条 2
像“幻觉”一样。
十三、查看事务隔离级别
1SELECT @@transaction_isolation; 2
十四、设置事务隔离级别
设置当前会话
1SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; 2
设置全局
1SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED; 2
十五、事务失效的常见原因(面试常问)
1. 忘记提交
1COMMIT; 2
没写。
2. 自动提交未关闭
1conn.setAutoCommit(false); 2
没写。
3. 异常未捕获
导致:
1rollback未执行 2
4. 数据库引擎不支持事务
例如:
1MyISAM 2
不支持事务。
十六、InnoDB 与 MyISAM
InnoDB(推荐)
支持:
- 事务
- 行锁
- 外键
MySQL 默认引擎。
MyISAM
不支持事务。
适合:
1读多写少 2
现在较少使用。
十七、Spring 事务(简单了解即可)
实际开发中,通常不会手写 JDBC 事务。
而是使用:
Spring 声明式事务
1@Transactional 2public void transfer(){ 3 4} 5
Spring 自动:
- 开启事务
- 提交事务
- 回滚事务
开发效率非常高。
十八、事务总结
核心一句话
事务就是保证多条SQL语句“要么全成功,要么全失败”。
事务控制语句
| 操作 | SQL |
|---|---|
| 开启事务 | START TRANSACTION |
| 提交事务 | COMMIT |
| 回滚事务 | ROLLBACK |
JDBC事务核心代码
1conn.setAutoCommit(false); 2 3conn.commit(); 4 5conn.rollback(); 6
MySQL 默认隔离级别
1Repeatable Read(可重复读) 2
开发中的最佳实践
推荐:
- 使用 InnoDB
- 使用 Spring 事务
- 捕获异常后 rollback
- 尽量缩小事务范围
十九、面试高频问题
1. 什么是事务?
事务是一组操作,要么全部成功,要么全部失败。
2. 事务四大特性?
1ACID 2
- 原子性
- 一致性
- 隔离性
- 持久性
3. MySQL 默认隔离级别?
1Repeatable Read 2
4. 如何开启事务?
1START TRANSACTION; 2
5. JDBC 如何控制事务?
1setAutoCommit(false) 2commit() 3rollback() 4
二十、学习建议
建议学习顺序:
1SQL事务 2↓ 3JDBC事务 4↓ 5事务隔离级别 6↓ 7Spring事务 8↓ 9分布式事务 10
这样会非常清晰。
《详解MySQL事务(超详细版)》 是转载文章,点击查看原文。