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就判定不需要更新了