MySQL一条更新语句是怎么执行的呢?

来分析下一个简单的update语句,update T set i = i + 1 where id = 100

一、锁

      Innodb引擎引擎支持表锁和行级锁的,id是主键,这时候只会锁住id=100这行数据,其他线程更新的话就要等到当前线程将锁释放掉。锁不是在事务开始的时候就获取,而是真正执行这条更新语句的时候才会获取锁,执行完也不会立即释放锁资源,而是事务提交的时候才会释放。如果如果两个事务同时开启的,那可重复读的隔离级别下,第二个执行更新的事务读到的是100还是101呢,是101,如果是100的话不就导致更新丢失了,更新读数据都是当前读,可以参考我的另一篇文章,事务的隔离级别是怎么实现的。你可能会有疑问,为什么不更新完就立即释放锁资源呢,这样就不会导致死锁了,其中的一个原因就是,事务可能执行失败要回滚的,你想一个事务100->101失败了,另一个101->102成功了,这样回滚起来基本是不太现实的。

二、执行过程

1. 首先执行器会根据主键索引找到id为100的数据,当然如果你的MySQL使用了缓存它会先从缓存中找,没有命中就会用主键找,如果内存页中没有这条数据,它会先把整个数据页都读到内存中,如果在内存页的话,直接在changebuffer中记录一条更新。

2.接着,执行器会调用相应的接口更改这条数据,将101的结果更新到内存中,然后将这个动作记录到redo日志里面,标记为prepar状态,表示随时可以提交。

3.然后执行器生成相应的binlog日志,写入binlog

4. redo日志为commit状态,提交

这就是Mysql的二阶段提交协议

写入redo的日志的速度是很快的,这个过程你不需要操作磁盘,可以将随机写磁盘转化为顺序写redo日志,减少了写的IO

如果3 4步骤之间数据库突然崩溃了,这时候数据库重启先看redo日志,有一条prepare的数据,它会根据相应的id尝试着去看binlog里面有没有相应的 数据,如果有的话redo日志会提交这条数据,没有的话redo日志会进行回滚,这和从binlog备份数据库得到的结果是一样的。

 

扫描二维码关注公众号,回复: 6012984 查看本文章

猜你喜欢

转载自blog.csdn.net/A1028151949/article/details/88045290