MySQL_事务与锁
MySQL事务与锁
前提条件
使用InnoDB引擎
目的
基于ACID原则,实现数据的可靠性与一致性
事务处理
流程图
graph TD
A[开始] --> B{设置 autocommit};
B -- autocommit=0 --> C[START TRANSACTION];
B -- autocommit=1 (默认) --> D[执行单条SQL自动提交];
C --> E[执行 SQL 语句序列];
E --> F{业务逻辑判断};
F -- 成功 --> G[COMMIT 提交事务];
F -- 失败/异常 --> H[ROLLBACK 回滚事务];
G --> I[事务结束,数据持久化];
H --> J[事务结束,数据恢复原状];示例
-- 1. 修改提交模式 [option] <0 is stop (手动提交), 1 is start (自动提交)
SET AUTOCOMMIT = 0;
-- 2. 显式开启事务
START TRANSACTION;
-- 3. 模拟业务操作:转账(A转给B 100元)
-- 注意:InnoDB引擎下,行锁是在执行SQL时自动获取的
UPDATE account SET balance = balance - 100 WHERE user_id = 1;
UPDATE account SET balance = balance + 100 WHERE user_id = 2;
-- 4. 判断是否要提交还是回滚
-- 假设这里有一个条件判断逻辑
IF (检查账户状态正常) THEN
COMMIT; -- 提交事务:Redo Log 落盘,事务结束
ELSE
ROLLBACK; -- 回滚事务:利用 Undo Log 恢复数据
END IF;
隔离处理
隔离性(即ACID原则的I原则)的核心目的是解决并发事务之间的干扰
MySQL通过锁机制和MVCC (多版本并发控制) 来实现不同级别的隔离
并发问题与隔离级别
并发问题定义:
- 脏读:读取到未提交的数据
- 不可重复读:两次查询结果不一致
- 幻读:两次范围查询结果不一致
| 隔离级别 | 英文名称 | 允许的现象 | 存在的问题 | 备注 |
|---|---|---|---|---|
| 读未提交 | Read Uncommitted | 脏读、不可重复读、幻读 | 能读取到未提交的数据 | 极度危险,任何公司都不允许 |
| 读已提交 | Read Committed | 不可重复读、幻读 | 两次查询结果可能不一致 | Oracle 默认 |
| 可重复读 | Repeatable Read | 无幻读 | 同一事务内读取结果一致 | InnoDB 默认级别 |
| 串行化 | Serializable | 无任何并发问题 | 强一致,性能极度低下 | 写操作必须排队,不推荐使用 |
| 隔离级别命令 |
| 操作类型 | SQL 命令 |
|---|---|
| 查看全局 | SELECT @@global.tx_isolation; |
| 查看当前会话 | SELECT @@tx_isolation; |
| 设置全局 | SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED; |
| 设置当前会话 | SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; |
锁
InnoDB 的锁是为了保证数据的一致性和隔离性,该目的可以被事务所承担,早期曾用作分布式锁,现锁的使用场景有限
锁的类型
| 分类维度 | 类型名称 | 说明 |
|---|---|---|
| 按范围 | 行锁 | 锁住一行数据 |
| 表锁 | 锁住一张表中所有的行 | |
| 按功能 | 共享锁 (读锁) |
读和读共享 读和写排他 |
| 排他锁 (写锁) |
写操作必须排他 | |
| 按机制 | 乐观锁 | 共享或排他都属于乐观锁 |
| 悲观锁 | 假定并发存在,通过数据库锁机制防止冲突 |