经典参考:https://blog.csdn.net/java_collect/article/details/105042975
binlog有几种格式?
三种,分别是
----statement:记录的是修改SQL语句(事物没提交也会记录,如果回滚则擦除)
----row:记录的是每行实际数据的变更(事物提交后的才算)
----mixed:statement和row模式的混合。
Mysql在5.0这个版本以前,binlog只支持STATEMENT这种格式!而这种格式在读已提交(Read Commited)这个隔离级别下主从复制是有bug的,因此Mysql将可重复读(Repeatable Read)作为默认的隔离级别!
binlog=STATEMENT,在读已提交下,主从复制有什么bug?
主从不一致性的问题!原因其实很简单,就是在master上执行的顺序为先删后插!而此时binlog为STATEMENT格式,它记录的顺序为先插后删!从(slave)同步的是binglog,因此从机执行的顺序和主机不一致!
读已提交情况下,binglog从管把执行的sql按顺序排列,不会管提交先后的顺序;可重复读有间隙锁,执行binglog的第二个会话内容时会锁等待
如何解决主从复制的bug?
解决方案有两种!
(1)改用可重复读(Repeatable Read),在该隔离级别下本身会引入间隙锁。当Session 1执行delete语句时,会锁住间隙条件范围。那么,Ssession 2执行插入语句就会阻塞住!
(2)还用读已提交,但将binglog的格式修改为row格式,此时是基于行的复制,自然就不会出现sql执行顺序不一样的问题!奈何这个格式在mysql5.1版本开始才引入。因此由于历史原因,mysql将默认的隔离级别设为可重复读(Repeatable Read),保证主从复制不出问题!
选读已提交的原因?
1)、repeatable存在间隙锁会使死锁的概率增大;
2)、在RR可重复读隔离级别下,条件列未命中索引会锁表!而在RC隔离级别下,只锁行;
在RR隔离级别下,走聚簇索引,进行全部扫描,最后会将整个表锁上;
在RC隔离级别下,其先走聚簇索引,进行全部扫描,但MySQL做了优化,在MySQL Server过滤条件,发现不满足后,会调用unlock_row方法,把不满足条件的记录放锁。
3)、在RC隔离级别下,引入半一致性读(semi-consistent)特性增加了update操作的性能!
半一致性读就是,一个update语句,如果读到一行已经加锁的记录,此时InnoDB返回记录最近提交的版本,由MySQL上层判断此版本是否满足update的where条件。若满足(需要更新),则MySQL会重新发起一次读操作,此时会读取行的最新版本(并加锁)!