mysql事务原理
一, 事务的隔离级别及解决的问题
隔离级别 | 含义说明 | 问题 | 时长 | 备注 | 其他 |
读未提交 | 1, 事务A修改了某个值但未提交事务 2, 事务B第一次读取这个值a 3, 然后事务A进行了撤销回滚 4, 事务B再次读取这个值不再是a | 脏读 | 较短时间 | 事务B的操作在一个事务下进行 | 无锁 |
读已提交 | 1, 事务A第一次读取某条数据值为null 2, 事务B修改了该条数据值为b并提交了事务 3, 事务A再次读取该条数据值为b 4, 事务C修改了该条数据值为c并提交了事务 5, 事务A再次读取该条数据值为c 1, 事务A第一次根据某些条件查询了一批数据 2, 事务B插入了一批数据 3, 事务A再次根据同一条件查询数据多了几条 | 不可重复读 (单纯从业务上来说其实也没有问题,其实大部分的项目也用该隔离机制) 幻读 | 较短时间 | 事务A的操作在一个事务下进行 | 行锁+mvcc解决不可重复读、脏读 |
可重复读 (Innodb默认) | 1, 事务A第一次根据某些条件查询了一批数据 2, 事务B插入了一批数据 3, 事务A再次根据同一条件查询数据一样 | 间隙锁+mvcc解决当前读幻读问题 | 较短时间 | 事务A的操作在一个事务下进行 | 间隙锁+mvcc解决幻读 |
串行化 | 所有的读写操作都会加锁 | 读写都加锁,性能极差 | 无 |
说明:
1, 一般的select 查询表示快照读,select * from xxx for update/share xxxx等表示当前读
2, oracle默认是读提交,如果存在数据库迁移切换,需要修改mysql的隔离级别
--------------------------------------------------------------------------------------------------
redo log、undo log、bing log
日志 | 位置 | 形式 | 记录方式 | 存在条件 | 文件大小 | 适用场景 |
Redo log | 引擎层 | 物理日志(数据页) | 循环写 | Innodb引擎 | 固定大小,重新覆盖 | 崩溃恢复 |
Undo log | 引擎层 | 相反sql(如 insert操作记录delete操作) | 追加写 | Innodb引擎 | 不限 | 事务恢复 MVCC(多版本并发控制)实现 |
Bing log | Server 层 | 逻辑日志(sql) | 追加写 | 所有引擎都有 | 不限,可指定每个bing log大小 | 主从复制+崩溃恢复 |
Bing log日志格式:
日志格式 | 版本 | 复制方式 | 优点 | 缺点 |
STATMENT | 5.7.7之前 | sql复制 | 减少日志量,节约IO,提高了性能 | 某些情况下可能导致主从不一致.如 执行了sysdate()、slepp等 |
ROW | 5.7.7之后 | 行复制 | 支持存储过程、function、trigger等复制 | 产生大量日志,尤其是alter table会让日志暴涨 |
MIXED | 5.7.7之后 | 混合复制 | 可规避前面两个的问题 |
WAL(write ahead logging)技术:
一条插入/更新语句的执行过程是: mysql客户端-》buffer pool(引擎层) -〉log buffer(redo log buffer/undo log buffer)-> OS buffer-> log files(redo log/undo log/bing log)
简单来说,就是因为写入log buffer是顺序IO,而刷盘是需要寻址的,是随机IO,顺序IO的性能比随机IO高很多,所以提高了系统的性能,即采用了同步写缓存日志异步刷盘的方式来保证性能.
Redo log记录日志过程:
Redo log循环记录日志是根据write pos与check point来定位的,write pos表示redo log当前记录的LSN(逻辑序列号)位置,check point表示数据页更改记录刷盘后对应redo log所处的LSN(逻辑序列号)位置。当write pos要追上check Point时会触发刷盘(刷盘是异步定时刷的)
崩溃恢复只要redo log 或者 只要bing log可以吗?
不能;
如果只要redo log, 理论上是可以的,因为redo log记录了数据页的变化位置,数据恢复落盘会更容易. 但redo log 不具备归档的能力,循环写数据不完整,从历史发展来看,mysql 最开始的MYISAM存储引擎是没有redo log的,但都有bing log日志归档,方便做数据的全量崩溃恢复.
如果只要bing log, bing log是存储的sql 逻辑日志,主要还是无法找到数据的磁盘位置,故无法进行数据恢复;
如果把redo log功能做到bing log里面,redo log去掉行不行?
想法是好的,可惜的是mysql最开始没有计划redo log并入bing log,从发展历史来看已不支持
二阶段提交:
sql执行-》....-》redo log(prepare阶段)-》bing log(就绪阶段)-》commit