mysql 的事务机制是保证数据库操作一致性和可靠性的核心特性,而隔离级别则用于平衡事务并发时的性能与数据一致性。
以下是详细解析:
一、事务的四大特性(acid)
事务(transaction)是一组不可分割的 sql 操作,要么全部成功,要么全部失败,核心依赖四大特性:
原子性(atomicity):
- 事务中的操作要么全部执行,要么全部回滚(如转账时,扣款和收款必须同时成功或失败)。
- 实现依赖:undo log(记录操作前的状态,用于回滚)。
一致性(consistency):
- 事务执行前后,数据从一个合法状态转换到另一个合法状态(如转账后总金额不变)。
- 由原子性、隔离性、持久性共同保证,部分依赖业务逻辑。
隔离性(isolation):
- 多个事务并发执行时,彼此的操作互不干扰(如避免同时修改同一行数据导致的混乱)。
- 实现依赖:锁机制(行锁、表锁)和 mvcc(多版本并发控制)。
持久性(durability):
- 事务提交后,修改永久保存(即使数据库崩溃也不丢失)。
- 实现依赖:redo log(记录操作后的状态,用于崩溃恢复)。
二、事务的隔离级别(sql 标准定义)
mysql 的隔离级别从低到高分为 4 种,级别越高,并发控制越严格,但性能开销越大:
隔离级别 | 脏读(dirty read) | 不可重复读(non-repeatable read) | 幻读(phantom read) | 说明 |
---|---|---|---|---|
读未提交(read uncommitted) | 可能发生 | 可能发生 | 可能发生 | 一个事务可读取另一个未提交的修改,极少使用(如实时数据监控场景)。 |
读已提交(read committed) | 不会发生 | 可能发生 | 可能发生 | 一个事务只能读取另一个已提交的修改(oracle 默认级别)。 |
可重复读(repeatable read) | 不会发生 | 不会发生 | 几乎不发生 | 事务中多次读取同一数据结果一致(mysql innodb 默认级别)。 |
串行化(serializable) | 不会发生 | 不会发生 | 不会发生 | 事务串行执行,完全避免并发问题,但性能极低(仅用于严格数据一致性场景)。 |
三、各隔离级别的典型场景与实现
1. 读未提交(read uncommitted)
- 场景:几乎不使用,仅适用于允许临时脏数据的极端场景(如实时统计)。
- 问题:事务 a 修改数据未提交,事务 b 读取到该 “脏数据”,若 a 回滚,b 读取的是无效数据。
2. 读已提交(read committed)
- 场景:大多数互联网应用(如电商订单查询,允许读取最新已提交数据)。
- 解决脏读:通过行锁保证,事务 a 修改数据时加锁,事务 b 只能读取 a 提交后的数据。
- 问题:不可重复读 —— 事务 b 两次读取同一行,期间事务 a 修改并提交,导致 b 两次结果不同。
3. 可重复读(repeatable read,mysql 默认)
- 场景:金融、支付等需保证多次读取一致性的场景(如对账时多次查询同一订单金额)。
- 解决不可重复读:通过 mvcc 实现,事务启动时生成数据快照,后续读取基于快照,不受其他事务提交影响。
- 对幻读的优化:innodb 通过 “间隙锁(gap lock)”+“临键锁(next-key lock)”,几乎避免幻读(特殊场景仍可能发生,但实际使用中可忽略)。
4. 串行化(serializable)
- 场景:数据一致性要求极高的场景(如银行核心交易)。
- 实现:强制事务按顺序执行(加表级锁),完全禁止并发,性能极低。
四、mysql 中设置与查看隔离级别
1. 查看当前隔离级别
-- mysql 8.0+ select @@transaction_isolation; -- mysql 5.7及以下 select @@tx_isolation;
2. 设置隔离级别(当前会话或全局)
-- 设置当前会话隔离级别 set session transaction isolation level 隔离级别名称; -- 设置全局隔离级别(需重新连接生效) set global transaction isolation level 隔离级别名称; -- 示例:设置当前会话为读已提交 set session transaction isolation level read committed;
五、事务控制语句
- 开启事务:
start transaction;
或begin;
- 提交事务:
commit;
(使修改永久生效) - 回滚事务:
rollback;
(放弃所有修改,恢复到事务开始前状态) - 保存点:
savepoint 保存点名称;
(事务中设置中间点,可回滚到指定点)
start transaction; update account set balance = balance - 100 where id = 1; savepoint sp1; -- 设置保存点 update account set balance = balance + 100 where id = 2; rollback to sp1; -- 回滚到保存点(仅撤销第二条更新) commit;
六、面试核心考点
- 默认隔离级别:mysql innodb 默认是可重复读(repeatable read),这是与其他数据库(如 oracle 默认读已提交)的重要区别。
- mvcc 与隔离级别的关系:mvcc 是实现可重复读和读已提交的核心机制,通过数据多版本快照避免加锁阻塞。
- 隔离级别与性能权衡:级别越高,一致性越好,但并发性能越差,实际应用中通常选择读已提交或可重复读。
- 幻读的处理:innodb 在可重复读级别通过间隙锁减少幻读,而串行化级别完全避免幻读。
理解事务机制和隔离级别,是设计高并发、高可靠数据库应用的基础,尤其在金融、电商等对数据一致性要求严格的场景中至关重要。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论