1.在MySQL发生异常重启的时候,是如何保证数据的完整性的

首先说数据的执行流程

图片

上面是一个update语句的执行流程,为何会调用commit语句的呢?.

上面的commit,指的是默认的commit步骤

一般update语句默认开启一个事务,完成事务的时候,就会用到commit步骤

接下来在两阶段提交的不同时刻,MySQL异常重启会出现什么现象

如果在A的地方,也就是写入redolog处于perpare时刻,写入binlog之前的时候,发生了崩溃,由于binLog还没有写入,所以redo log并不会提交,在崩溃恢复的时候,事务会回滚,这时候binLog没有写,所以不会传给备库中

如果在B里面,那么如果在B的时候,也就是写完了binLog,但是没有commit之前发生了crash,如何进行处理呢

那么处理逻辑很简单,在恢复的时候,如果redolog中的事务是完整的,那么会直接提交

如果reodolog中的事务是一个perpare,则判断对应的binLog是否存在,如果存在则提交,不然 回滚事务

那么下一个问题,就是MySql如何判断binlog是完整的

如果是statement的binlog,会在最后出现一个commit

如果是row格式的binlog,则最后会有一个XID event

在MySQ5.6版本后,引入了binlog-checksum参数,用于验证binlog的正确性,对于可能日志中间出错的情况,可以通过检验checksum来判断

2.redo log和binlog如何关联的

是通过一个共同的字段XID进行关联的

如果碰到既有prepare的又有commit的redolog,就直接提交

如果碰到只有prepare,但没有commit的redolog,拿着XID去binlog找对应事务

为何不设计为先写完redolog,再去写binlog,崩溃恢复的时候,必须两个日志都完整才行

这是因为这个两阶段提交是经典的分布式系统问题,并不是MySQL独有

对于InnoDB引擎,如果redolog提交了,事务就不能回滚,如果redolog提交了,binLog没有写,这时候异常了,导致binlog并不完整,而备库则是按照binlog去写入的,于是两阶段提交就是给所有人一个机会,告诉所有人我ok了,说到底,还是因为InnoDB并不是原生的引擎的原因

3.如果只是用binlog日志进行恢复呢?

只保留binlog来进行事务的更新和崩溃后的回滚的话

会参考MyISAM,MyISAM只有binLog日志,以至于其没有崩溃恢复的功能

而InnoDB在加入MySQL之前,就已经提供了崩溃恢复了,于是可以直接使用InnoDB的redolog功能来进行恢复

而如果没有binlog的话,如果两个事务发生了错误,回滚可能如下

图片

可能出现binlog2事务写完了,但是整体事务没有commit的时候,MySQL发生了crash,在数据库重启后,事务2会被回滚,但是事务1并不会应用一次binlog,因为InnoDB采用了WAL技术,执行事务的时候,写完内存和日志,事务就算完成了,恢复需要依赖日志,但是binlog日志并没有记录数据页的更新细节,是不会修补的

如果直接使用redo log进行恢复

MySQL的主从备份依赖于binlog,如果关掉,就没法主从备份了

4.redolog的大小设置为多少

如果硬盘足够的,一般情况下,设置为4个文件,每个文件1GB

5.下述的流程,是先修改内存还是先写redolog呢?

图片

其实往表里面插入两个记录,在插入数据的过程中,生成的日志都需要先进行保存,但不能直接写入redolog文件

先写在redo log buffer之中,然后执行commit的时候,去写入redo log文件

6.一个业务设计相关的问题

业务上有一个需求,两个用户AB,如果互相关注,则成为好友 设计上有两张表,一个是like,一个是friend表

执行如下的逻辑:

如果A关注了B

查询对方有没有关注自己

select * from like where user_id = B and liker_id =A

如果如果有,则成为好友

insert into friend

没有,则成为了单向关注的情况

但是有一种情况,如果AB同时关注对方,会导致两者不会成为好友,如何解决这个问题呢

解决方案如下:

可以考虑维护这样一种关系,先给like表中增加一个字段,relation_ship 并取整型作为字段

在实际代码中表示

值为1的时候,表示user_id关注like_id

值为2的时候,表示like_id关注user_id

值为3的时候,互关

永远保证用户id小的为user_id,利用或运算,来进行相关的状态比较

1|2 = 3, 1|3 = 3

7.对于一个数据,已经是(1,2)了,那么我们再次更新这个数据为(1,2),MySql会进行更新吗

答案是会的

关于这一点,我们可以通过一个锁来时延

图片

sessionB被blocked说明,mysql尝试去更新了

这是由于了一致性快照和多版本共存的机制,导致了

一个Session在执行过程中,只能看见本Session的操作,看不见其他的Session操作,所以判断需要进行更新

但是,如果你传递的Where条件足够满足判断的话,就不会进行更新啦

图片

明确要求id为(1,3)的,mysql就判定不需要更新了

发表评论

邮箱地址不会被公开。 必填项已用*标注