it编程 > 数据库 > Mysql

深入解析MySQL中默认的事务隔离级别与选择原因

2人参与 2026-08-07 Mysql

mysql 默认的事务隔离级别是 可重复读(repeatable read)。这是 mysql innodb 存储引擎的默认设置,也是 mysql 与其他数据库(如 oracle、postgresql 默认使用 read committed)的重要区别。

一、为什么选择 repeatable read 作为默认级别?

1. 保证数据一致性的最佳平衡

-- 在 repeatable read 级别下:
-- 事务 a
start transaction;
select * from accounts where user_id = 1; -- 第一次查询

-- 事务 b(同时执行)
start transaction;
update accounts set balance = balance + 100 where user_id = 1;
commit;

-- 事务 a 再次查询
select * from accounts where user_id = 1; -- 结果与第一次相同(不可重复读被解决)
commit;

优势

2. 适应 mysql 主从复制架构

mysql 的复制机制(特别是基于语句的复制)要求:

-- 主库执行(基于语句的复制)
start transaction;
insert into orders values (1, 'pending');
-- 此时其他事务修改了数据
update orders set status = 'shipped' where id = 1;
commit;

-- 从库重放 binlog 时,需要保证 update 语句看到的数据与主库一致
-- repeatable read 的快照机制保证了这一点

3. innodb 的 mvcc 实现优势

innodb 通过 多版本并发控制(mvcc) 实现 repeatable read:

-- mvcc 工作原理简示
-- 数据行结构
| id | name | balance | trx_id | roll_pointer |
|----|------|---------|--------|--------------|
| 1  | alice| 1000    | 100    | 指向旧版本   |

-- 事务 101 读取时:
-- 1. 创建 read view(包含活跃事务列表)
-- 2. 只读取 trx_id < 101 且已提交的数据
-- 3. 通过 undo log 构造历史版本

mvcc 在 repeatable read 下的特点

4. 历史兼容性和应用习惯

二、不同隔离级别的对比

隔离级别脏读不可重复读幻读innodb 实现机制
read uncommitted❌ 可能❌ 可能❌ 可能无锁读取最新数据
read committed✅ 防止❌ 可能❌ 可能每次 select 创建新 read view
repeatable read (默认)✅ 防止✅ 防止⚠️ 部分防止事务开始创建 read view + next-key lock
serializable✅ 防止✅ 防止✅ 防止所有 select 自动加锁

三、repeatable read 的实际效果

1. 快照读(一致性非锁定读)

-- 事务 a
start transaction; -- 创建 read view

-- 此时数据:id=1, balance=1000
select balance from accounts where id = 1; -- 返回 1000

-- 事务 b 修改数据并提交
start transaction;
update accounts set balance = 2000 where id = 1;
commit;

-- 事务 a 再次读取(不可重复读被防止)
select balance from accounts where id = 1; -- 仍然返回 1000
commit;

-- 事务提交后读取最新数据
select balance from accounts where id = 1; -- 返回 2000

2. 当前读(锁定读)

-- 使用 for update 或 lock in share mode 进行当前读
start transaction;
select * from accounts where id = 1 for update; -- 获取最新数据并加锁

-- 其他事务的 update 会被阻塞

3. 幻读的防止

-- 事务 a
start transaction;
select * from users where age > 20; -- 返回 5 条记录

-- 事务 b 插入新记录
start transaction;
insert into users (name, age) values ('bob', 25); -- 会被阻塞(next-key lock)
commit; -- 等待事务 a 释放锁

-- 事务 a 再次查询
select * from users where age > 20; -- 仍然返回 5 条记录
commit; -- 释放锁,事务 b 的插入才能执行

四、如何查看和修改隔离级别

查看当前隔离级别

-- 查看全局隔离级别
select @@global.transaction_isolation;

-- 查看会话隔离级别
select @@session.transaction_isolation;

-- 查看当前连接的隔离级别
select @@transaction_isolation;

-- 输出示例:repeatable-read

修改隔离级别

-- 修改当前会话的隔离级别
set session transaction isolation level read committed;

-- 修改全局隔离级别(重启后生效)
set global transaction isolation level read committed;

-- 或在 my.cnf 中配置
[mysqld]
transaction-isolation = read-committed

五、什么时候应该调整隔离级别?

推荐使用 read committed 的场景

-- 1. 高并发写入场景
set session transaction isolation level read committed;
start transaction;
-- 较少的锁冲突,更高的并发度

-- 2. 使用基于行的复制(row-based replication)
-- 需要配合修改配置
set global binlog_format = 'row';

-- 3. oracle 迁移到 mysql 的应用
-- 保持与 oracle 默认行为一致

坚持使用 repeatable read 的场景

-- 1. 金融交易系统(需要高度一致性)
start transaction;
-- 多次读取余额必须一致

-- 2. 报表系统(需要一致的数据视图)
start transaction;
-- 生成报表期间数据不应变化

-- 3. 使用基于语句的复制(默认)
-- 保证主从数据一致性

六、注意事项和最佳实践

1. 长事务问题

-- 长事务在 repeatable read 下会导致问题
start transaction;
select * from large_table; -- 创建快照

-- 长时间不提交...
-- 结果:undo 日志堆积,影响性能
-- 建议:设置事务超时
set session max_execution_time = 5000; -- 5秒超时

2. 监控和调优

-- 监控长事务
select 
    trx_id,
    trx_started,
    timediff(now(), trx_started) as duration,
    trx_state
from information_schema.innodb_trx
order by trx_started;

-- 查看锁等待
select * from information_schema.innodb_lock_waits;

3. 应用程序适配

// spring boot 中配置隔离级别
@configuration
public class datasourceconfig {
    
    @bean
    public platformtransactionmanager transactionmanager(datasource datasource) {
        datasourcetransactionmanager tm = new datasourcetransactionmanager(datasource);
        tm.setdefaulttimeout(30); // 设置超时
        tm.setdefaultisolationlevel(transactiondefinition.isolation_repeatable_read);
        return tm;
    }
}

// 或在具体方法上指定
@transactional(isolation = isolation.read_committed, timeout = 10)
public void updateaccount(account account) {
    // ...
}

七、与其他数据库的对比

数据库默认隔离级别备注
mysql (innodb)repeatable readmvcc + next-key lock 实现
oracleread committed多版本读一致性实现不同
postgresqlread committed使用 mvcc,但默认级别不同
sql serverread committed可通过快照隔离提升

总结

mysql 选择 repeatable read 作为默认隔离级别,主要基于:

  1. 数据一致性:提供了脏读和不可重复读的防止,适应大多数应用场景
  2. 复制兼容:配合基于语句的复制,保证主从数据一致性
  3. 性能平衡:mvcc 实现读不加锁,写操作通过 next-key locking 防止幻读
  4. 历史兼容:长期默认设置,生态系统已适应

最佳实践建议

理解隔离级别的选择对于设计高性能、高可用的 mysql 应用至关重要。

以上就是深入解析mysql中默认的事务隔离级别与选择原因的详细内容,更多关于mysql事务隔离级别的资料请关注代码网其它相关文章!

(0)

您想发表意见!!点此发布评论

推荐阅读

从入门到实战详解MySQL中字符串处理函数完全指南

08-07

MySQL在CentOS7环境下的安装步骤教程(含详细代码)

08-07

Nginx第三方模块故障排查指南(模块编译与加载问题解决)

08-06

基于Nginx的API网关基础配置与实现方案

08-06

Nginx第三方模块编译与添加方法

08-06

MySQL SQL调优的方法及具体技巧详细讲解

08-06

猜你喜欢

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论