mysql rc模式時binlog_format=row的解釋【轉】


總體來說:在 tx_isolation= READ-COMMITTED 、binlog_format =statement 的情況下,mysql 沒有gap 鎖,這樣binlog 記錄的數據修改的順序可能會導致 復制環境的 slave 數據和master 數據不一致。

模擬步驟

數據初始化

 CREATE TABLE `gapt` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(32) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `ind_name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8;
mysql> select * from gapt; +----+------+ | id | name | +----+------+ | 1 | 1 | | 10 | 10 | | 11 | 11 | | 15 | 15 | | 2 | 2 | | 3 | 3 | | 4 | 4 | | 5 | 5 | | 6 | 6 | | 8 | 8 | | 9 | 9 | +----+------+ 

session1 和 session2 模擬

@session 1:
mysql> show variables like '%tx_isolation%'; +---------------+----------------+ | Variable_name | Value | +---------------+----------------+ | tx_isolation | READ-COMMITTED | +---------------+----------------+ 1 row in set (0.00 sec) mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> update gapt set id=name+20 where name between 5 and 11; Query OK, 6 rows affected (0.00 sec) Rows matched: 6 Changed: 6 Warnings: 0 @session2 mysql> show variables like '%tx_isolation%'; +---------------+----------------+ | Variable_name | Value | +---------------+----------------+ | tx_isolation | READ-COMMITTED | +---------------+----------------+ 1 row in set (0.00 sec) mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> insert into gapt select 24,5; Query OK, 1 row affected (0.00 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql> commit; Query OK, 0 rows affected (0.00 sec) mysql> system date Fri Jun 19 10:55:38 CST 2015 @session1 mysql> select * from gapt where name between 5 and 11; +----+------+ | id | name | +----+------+ | 30 | 10 | | 31 | 11 | | 24 | 5 | | 25 | 5 | | 26 | 6 | | 28 | 8 | | 29 | 9 | +----+------+ 7 rows in set (0.00 sec) #你會發現 6行變成7行了, mysql> system date; Fri Jun 19 10:55:50 CST 2015 mysql> commit; Query OK, 0 rows affected (0.00 sec) 

重點: 兩個 session 執行完 commit,並且按照 binlog_format = statement 日志模式的話,那么最終的binlog日志記錄應該是按照事務 commit 的順序記錄的。

#binlog 實際存儲的執行順序
@session2 
mysql> begin;
Query OK, 0 rows affected (0.00 sec) mysql> insert into gapt select 24,5; Query OK, 1 row affected (0.00 sec) Records: 1 Duplicates: 0 Warnings: 0 mysql> commit; Query OK, 0 rows affected (0.00 sec) #session1 mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> update gapt set id=name+20 where name between 5 and 11; Query OK, 6 rows affected (0.00 sec) mysql> commit; 

如果是這樣記錄的話你會發現這個 @session1 的 update 語句會把 session2 剛剛插入的 name='5',id=24 數據也會更新掉了!!這也就導致了(如果有復制)從庫從庫的數據就會和復制的主庫不一樣了!!

問題來了,我是如何模擬的呢?我是設置 tx_isolation=READ-COMMITTED binlog_format= MIXED 的時候,上面的操作可以正確執行,這是因為 MySQL 識別到了這個可能存在不一致的復制情況,就把上面的操作轉換成了 binlog_format=row 的二進制日志。

#150619 10:55:00 server id 4306 end_log_pos 283 Table_map: `repl`.`gapt` mapped to number 52 #150619 10:55:00 server id 4306 end_log_pos 319 Write_rows: table id 52 flags: STMT_END_F BINLOG ' hISDVRPSEAAALgAAABsBAAAAADQAAAAAAAEABHJlcGwABGdhcHQAAgMPAmAAAg== hISDVRfSEAAAJAAAAD8BAAAAADQAAAAAAAEAAv/8GAAAAAE1 '/*!*/; # at 319 #150619 10:55:09 server id 4306 end_log_pos 346 Xid = 447 #session2 的 commit COMMIT/*!*/; # at 346 #150619 10:57:04 server id 4306 end_log_pos 414 Query thread_id=16 exec_time=0 error_code=0 SET TIMESTAMP=1434682624/*!*/; BEGIN /*!*/; # at 414 # at 460 #150619 10:54:14 server id 4306 end_log_pos 460 Table_map: `repl`.`gapt` mapped to number 52 #150619 10:54:14 server id 4306 end_log_pos 578 Update_rows: table id 52 flags: STMT_END_F BINLOG ' VoSDVRPSEAAALgAAAMwBAAAAADQAAAAAAAEABHJlcGwABGdhcHQAAgMPAmAAAg== VoSDVRjSEAAAdgAAAEICAAAAADQAAAAAAAEAAv///AUAAAABNfwZAAAAATX8BgAAAAE2/BoAAAAB NvwIAAAAATj8HAAAAAE4/AkAAAABOfwdAAAAATn8CgAAAAIxMPweAAAAAjEw/AsAAAACMTH8HwAA AAIxMQ== '/*!*/; # at 578 #150619 10:57:04 server id 4306 end_log_pos 605 Xid = 443 #session1 的 commit COMMIT/*!*/; 

binlog_format 為什么轉化為 row 就可以呢,因為 row 格式的日志記錄的是底層數據真正的變化,這樣就不會導致復制環境的主從數據不一致了。

ps: 如果有什么理解錯誤的,或者模擬的不合理的地方,麻煩糾正指出來,謝謝。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM