当前位置: 代码网 > it编程>数据库>Mysql > 深入解析MySQL中默认的事务隔离级别与选择原因

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

2026年08月07日 Mysql 我要评论
mysql 默认的事务隔离级别是 可重复读(repeatable read)。这是 mysql innodb 存储引擎的默认设置,也是 mysql 与其他数据库(如 oracle、postgresql

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;

优势

  • 防止不可重复读:同一事务内多次读取同一数据,结果一致
  • 防止脏读:不会读取未提交的数据
  • 一定程度防止幻读:通过 mvcc + next-key locking 机制

2. 适应 mysql 主从复制架构

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

  • binlog 格式:默认使用基于语句的复制(statement-based replication)
  • 可重复读确保一致性:在 repeatable read 下,事务内的 select 看到的是同一快照,使得 binlog 中的语句在从库重放时结果一致
-- 主库执行(基于语句的复制)
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 下的特点

  • 事务开始时创建 read view,整个事务期间都使用这个快照
  • 读操作不需要加锁,提高并发性能
  • 写操作使用 next-key locking 防止幻读

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

  • 历史原因:早期 mysql 的 myisam 不支持事务,innodb 引入后选择了与标准 sql 一致的默认级别
  • 应用习惯:许多 php、java 应用基于 mysql 开发,默认级别已被广泛接受

二、不同隔离级别的对比

隔离级别脏读不可重复读幻读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. 历史兼容:长期默认设置,生态系统已适应

最佳实践建议

  • 大多数情况:使用默认的 repeatable read
  • 高并发写入:考虑切换到 read committed + row 格式 binlog
  • 金融系统:保持 repeatable read,注意长事务控制
  • 迁移应用:根据源数据库特性调整隔离级别

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

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

(0)

相关文章:

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

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com