Mysql如何执行一次Update

1,234 阅读3分钟

在Mysql中我们Java系统执行一次更新SQL如:update Users set name="张三" where id=1 首先还是获取数据库连接池连接,创建好连接后发送sql语句到Mysql连接池。然后mysql创建一个线程处理,通过SQL接口、解释器、优化器、执行器、最后执行器调用存储引擎去访问数据。不太明白的小伙伴请看 juejin.cn/post/692046… 下面我们讨论一下InnoDB的内部结构。

Buffer Pool(缓冲池)

Buffer Pool是存储引擎(InnoDB)最重要的内存组件其目的是提高mysql读取性能,我们需要修改的数据如果存在于Buffer Pool 中就直接进行修改,若是不存在就会从磁盘中加载进来。

undo-Log

现在开始修改数据,但是原来name=“王麻子” 现在修改为 “张三” 我们还没有修改完成之前是不是要考虑撤销的问题,所以我们需要把修改前 name=“王麻子” 先存在一个地方。这个为了撤销(回滚)修改而准备的日志文件就是undo-Log。现在我把旧值提前写入Undo-Log 并加上了独占锁,如果数据不在Buffer Pool中就从磁盘文件中加载进来。 修改成功数据已经在BufferPool中更新为了name=“张三”。

redo-Log Buffer

数据已经修改成功我们思考一个问题缓存区中的数据其实是脏数据,因为磁盘文件中数据并没有更新为“张三” 如果数据库突然宕机是否数据就丢失了。这个时候我们在Buffer-Pool 中所作的修改会被存储到redo-Log Buffer 中避免突然宕机导致的数据丢失。但是redo-log Buffer也是一个内存中的组件宕机了它自己都“自身难保” 那怎么办? 其实不用急因为我们的数据虽然修改了但是我们并未提交事务,事务未提交前数据丢失了不重要的嘛。早事务提交的时候我们会吧redo-log buffer 中的记录写入到 redo-Log 文件中。 当然这个写入也是有策略的,通过配置InnoDB_flush_log_at_trx_commit 等于1.

binLog

其实redolog是偏向物理性质的重做日志,里面记录了对那个数据页做了什么修改了什么,它本身属于innoDB存储引擎本身。而binlog是逻辑性质的日志记录了你对那个表新增了记录、或者对那个表删除了记录 类似 delete from User where id=2 binlog本身是属于Mysql server的。我们提交了事务的时候会同时将日志写入binlog,对于binlog而言也是有策略配置的sync_binlog 参数可以控制binlog的写入策略。它的默认值是0 表示 提交事务的时候不会立刻将binlog日志数据写入磁盘而是将其先写入OS Cache 。如果这个时候宕机的话是会造成binlog数据丢失的。如果将sync_binlog配置为1 是可以在提交事务的时候立刻将日志写入磁盘中进行持久化的,不存在丢失数据问题。当我们的binlog都写入磁盘之后会把此时会把本次更新对应的binlog文件名称和更新的binlog日志在文件里的位置写入到redolog文件里去,同时在redo log日志文件里写入一个commit标记。

为什么需要Commit标记

其实就是为了保证redolog与binlog日志一致的。 只有最终未写入commit标记就代表本次事务是失败的。最后后台IO线程随机的将buffer pool中的变更后的数据写入到数据文件中。