MySQL半一致性讀導致語句級Binlog複製錯誤
MySQL事務的隔離級別為read committed(或以下),或者設定了innodb_locks_unsafe_for_binlog引數會啟用半一致性讀特性。
半一致性讀參考:
http://hedengcheng.com/?p=220
MySQL官方文件refman-5.6-en.a4.pdf 1833頁 關於innodb_locks_unsafe_for_binlog引數
對於半一致性讀,我感覺一個是違反兩階段鎖,將不符合條件記錄的行級鎖提前釋放。另一個是Update的行如果被鎖定,則返回一個最近提交的版本。
官方文件原文如下:
Enabling innodb_locks_unsafe_for_binlog has additional effects:
? For UPDATE or DELETE statements, InnoDB holds locks only for rows that it updates or deletes.
Record locks for nonmatching rows are released after MySQL has evaluated the WHERE condition.
This greatly reduces the probability of deadlocks, but they can still happen.
? For UPDATE statements, if a row is already locked, InnoDB performs a “semi-consistent” read,
returning the latest committed version to MySQL so that MySQL can determine whether the row
matches the WHERE condition of the UPDATE. If the row matches (must be updated), MySQL reads
the row again and this time InnoDB either locks it or waits for a lock on it.
半一致性讀本身是為了增加併發,但是對於STATEMENT格式的binlog則是致命的錯誤。
實驗環境如下:
初始化資料
CREATE TABLE t (a INT NOT NULL, b INT) ENGINE = InnoDB;
INSERT INTO t VALUES (1,2),(2,3),(3,2),(4,3),(5,2);
COMMIT;
mysql> select * from t;
+---+------+
| a | b |
+---+------+
| 1 | 2 |
| 2 | 3 |
| 3 | 2 |
| 4 | 3 |
| 5 | 2 |
+---+------+
5 rows in set (0.00 sec)
開啟一個終端A,將b=3的記錄修改為10
然後開啟另外一個終端B,將b=2的記錄修改為3並且提交,
最後提交終端A的事務。
檢視此時的結果
mysql> select * from t;
+---+------+
| a | b |
+---+------+
| 1 | 3 |
| 2 | 10 |
| 3 | 3 |
| 4 | 10 |
| 5 | 3 |
+---+------+
5 rows in set (0.00 sec)
這個結果沒有任何問題,但是檢視binlog的內容
BEGIN
/*!*/;
# at 2802
#140215 0:07:52 server id 1 end_log_pos 2906 CRC32 0x264b3682 Query thread_id=2 exec_time=0 error_code=0
SET TIMESTAMP=1392394072/*!*/;
update t set b=3 where b=2
/*!*/;
# at 2906
#140215 0:07:54 server id 1 end_log_pos 2937 CRC32 0x59a3d24d Xid = 63
COMMIT/*!*/;
# at 2937
#140215 0:06:02 server id 1 end_log_pos 3020 CRC32 0x56a9493b Query thread_id=3 exec_time=0 error_code=0
SET TIMESTAMP=1392393962/*!*/;
BEGIN
/*!*/;
# at 3020
#140215 0:06:02 server id 1 end_log_pos 3125 CRC32 0x0d874b5d Query thread_id=3 exec_time=0 error_code=0
SET TIMESTAMP=1392393962/*!*/;
update t set b=10 where b=3
/*!*/;
# at 3125
#140215 0:08:01 server id 1 end_log_pos 3156 CRC32 0x8fe0dd5d Xid = 61
COMMIT/*!*/;
如果使用binlog複製,則備庫執行的語句如下:
CREATE TABLE t (a INT NOT NULL, b INT) ENGINE = InnoDB;
INSERT INTO t VALUES (1,2),(2,3),(3,2),(4,3),(5,2);
COMMIT;
update t set b=3 where b=2;
commit;
update t set b=10 where b=3;
commit;
備庫執行後的資料則是
mysql> select * from t;
+---+------+
| a | b |
+---+------+
| 1 | 10 |
| 2 | 10 |
| 3 | 10 |
| 4 | 10 |
| 5 | 10 |
+---+------+
5 rows in set (0.00 sec)
為了避免這個問題,可以將binlog_format設定為ROW。
半一致性讀參考:
http://hedengcheng.com/?p=220
MySQL官方文件refman-5.6-en.a4.pdf 1833頁 關於innodb_locks_unsafe_for_binlog引數
對於半一致性讀,我感覺一個是違反兩階段鎖,將不符合條件記錄的行級鎖提前釋放。另一個是Update的行如果被鎖定,則返回一個最近提交的版本。
官方文件原文如下:
Enabling innodb_locks_unsafe_for_binlog has additional effects:
? For UPDATE or DELETE statements, InnoDB holds locks only for rows that it updates or deletes.
Record locks for nonmatching rows are released after MySQL has evaluated the WHERE condition.
This greatly reduces the probability of deadlocks, but they can still happen.
? For UPDATE statements, if a row is already locked, InnoDB performs a “semi-consistent” read,
returning the latest committed version to MySQL so that MySQL can determine whether the row
matches the WHERE condition of the UPDATE. If the row matches (must be updated), MySQL reads
the row again and this time InnoDB either locks it or waits for a lock on it.
半一致性讀本身是為了增加併發,但是對於STATEMENT格式的binlog則是致命的錯誤。
實驗環境如下:
初始化資料
CREATE TABLE t (a INT NOT NULL, b INT) ENGINE = InnoDB;
INSERT INTO t VALUES (1,2),(2,3),(3,2),(4,3),(5,2);
COMMIT;
mysql> select * from t;
+---+------+
| a | b |
+---+------+
| 1 | 2 |
| 2 | 3 |
| 3 | 2 |
| 4 | 3 |
| 5 | 2 |
+---+------+
5 rows in set (0.00 sec)
開啟一個終端A,將b=3的記錄修改為10
然後開啟另外一個終端B,將b=2的記錄修改為3並且提交,
最後提交終端A的事務。
檢視此時的結果
mysql> select * from t;
+---+------+
| a | b |
+---+------+
| 1 | 3 |
| 2 | 10 |
| 3 | 3 |
| 4 | 10 |
| 5 | 3 |
+---+------+
5 rows in set (0.00 sec)
這個結果沒有任何問題,但是檢視binlog的內容
BEGIN
/*!*/;
# at 2802
#140215 0:07:52 server id 1 end_log_pos 2906 CRC32 0x264b3682 Query thread_id=2 exec_time=0 error_code=0
SET TIMESTAMP=1392394072/*!*/;
update t set b=3 where b=2
/*!*/;
# at 2906
#140215 0:07:54 server id 1 end_log_pos 2937 CRC32 0x59a3d24d Xid = 63
COMMIT/*!*/;
# at 2937
#140215 0:06:02 server id 1 end_log_pos 3020 CRC32 0x56a9493b Query thread_id=3 exec_time=0 error_code=0
SET TIMESTAMP=1392393962/*!*/;
BEGIN
/*!*/;
# at 3020
#140215 0:06:02 server id 1 end_log_pos 3125 CRC32 0x0d874b5d Query thread_id=3 exec_time=0 error_code=0
SET TIMESTAMP=1392393962/*!*/;
update t set b=10 where b=3
/*!*/;
# at 3125
#140215 0:08:01 server id 1 end_log_pos 3156 CRC32 0x8fe0dd5d Xid = 61
COMMIT/*!*/;
如果使用binlog複製,則備庫執行的語句如下:
CREATE TABLE t (a INT NOT NULL, b INT) ENGINE = InnoDB;
INSERT INTO t VALUES (1,2),(2,3),(3,2),(4,3),(5,2);
COMMIT;
update t set b=3 where b=2;
commit;
update t set b=10 where b=3;
commit;
備庫執行後的資料則是
mysql> select * from t;
+---+------+
| a | b |
+---+------+
| 1 | 10 |
| 2 | 10 |
| 3 | 10 |
| 4 | 10 |
| 5 | 10 |
+---+------+
5 rows in set (0.00 sec)
為了避免這個問題,可以將binlog_format設定為ROW。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29254281/viewspace-1081678/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- MySQL 網路導致的複製報錯案例MySql
- MySQL半同步複製資料最終一致性驗證MySql
- MySQL 主從複製,常見的binlog錯誤及解決方法MySql
- MySQL#複製 - 原生複製的一致性探討MySql
- 半同步複製報錯mysql8.0.25MySql
- MySQL 主從複製錯誤1837MySql
- 解讀MySQL雙主複製的主備資料一致性GPMySql
- MySQL GTID複製錯誤修復演示MySql
- MySQL 8 複製(二)——半同步複製MySql
- MySQL主從複製錯誤——列型別轉換錯誤MySql型別
- MySQL5.7半同步複製報錯案例分析MySql
- MySQL e二級索引上的一致性讀MySql索引
- mysql 5.7半同步複製MySql
- MySQL主從複製之半同步複製MySql
- MySQL半一致性讀原理解析-從原始碼角度解析MySql原始碼
- 升級Xcode10導致的編譯錯誤XCode編譯
- Mysql5.7半同步複製MySql
- 淺複製導致的bug
- MySQL5.7主從複製-半同步複製搭建MySql
- MySQL_通過binlog檢視原始SQL語句MySql
- MySQL8.0的一個bug導致複製延時MySql
- mysql多源複製跳過錯誤處理方法MySql
- mysql半同步複製的設定MySql
- 複製錯誤案例分享(一)
- 複製錯誤案例分享(二)
- 故障分析 | 手動 rm 掉 binlog 導致主從報錯
- Linux下MySQL主從複製(Binlog)的部署過程LinuxMySql
- MySQL:MGR修改max_binlog_cache_size引數導致異常MySql
- #MySQL# mysql5.7新特性之半同步複製MySql
- Binlog多大導致主從中斷
- MySQL增強(Loss-less)半同步複製MySql
- SqlServer 主從複製錯誤分析--20598SQLServer
- 解決程式碼中重複的捕獲 promise 錯誤的 try catch 語句Promise
- Lombok 的@ToString導致的Maven編譯錯誤LombokMaven編譯
- ORA-04031錯誤導致當機案例分析
- 透過延時從庫+binlog複製,恢復誤運算元據
- 05、MySQL Case-MySQL binlog誤清除恢復MySql
- 複製表結構和資料SQL語句SQL
- MySQL探祕(六):InnoDB一致性非鎖定讀MySql