【20181101】MySQL text型別的column設定為NOT NULL 導致主從1364
環境
系統版本 : CentOS release 6.8 (Final)
MySQL版本:5.6.29-log MySQL Community Server (GPL)
MySQL主從配置資訊
- binlog format :MIXED
- sql_mode: NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
問題描述
從庫show slave status監控的時候發現sql_thread程序已經變成NO,並且爆出了1362錯誤,仔細檢視報錯的是一條insert into語句,並且丟擲了一個詳細的錯誤,大致的意思就是欄位column_1設定了NOT NULL但是沒有插入值並且沒有預設值。然後仔細檢查了一下表結構,具體資訊如下
- 欄位column_1的確設定的是NOT NULL並且沒有設定default 預設值。
- column_1欄位是是text型別,所以是無法設定defaut預設值。
本地環境手動執行驗證
在看到這個報錯的資訊的時候,直接google了一下,大部分答案顯示都是由於sql_mode的原因所導致的,要想解決這個問題,必須將執行:
mysql> set global sql_mode="NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION";
但是我在slave獲取得到的sql_mode就是 NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
猜想
這個時候我就想這個是否在主從複製的過程中,slave在執行這個insert插入的時候sql_mode發生了更改了,這個時候我解析slave的relay log資訊獲取得到 :
# at 271 #181019 12:13:00 server id 5403005 end_log_pos 319 CRC32 0x755a7204 GTID [commit=yes] SET @@SESSION.GTID_NEXT= '8e91de47-8f0b-11e8-824c-246e9699bb48:1408667354'/*!*/; # at 319 #181019 12:13:00 server id 5403005 end_log_pos 440 CRC32 0x1add7880 Query thread_id=47560669 exec_time=0 error_code=0 SET TIMESTAMP=1539922380/*!*/; SET @@session.pseudo_thread_id=47560669/*!*/; SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/; SET @@session.sql_mode=1344274432/*!*/; SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/; /*!\C utf8mb4 *//*!*/; SET @@session.character_set_client=45,@@session.collation_connection=45,@@session.collation_server=45/*!*/; SET @@session.time_zone='SYSTEM'/*!*/; SET @@session.lc_time_names=0/*!*/; SET @@session.collation_database=DEFAULT/*!*/; BEGIN /*!*/; # at 440 #181019 12:13:00 server id 5403005 end_log_pos 689 CRC32 0x1537384f Query thread_id=47560669 exec_time=0 error_code=0 use `finance_fixin_product`/*!*/; SET TIMESTAMP=1539922380/*!*/; ..... ..... ..... /*!*/;
可以很明顯的得到在上面binlog中有一個 SET @@session.sql_mode=1344274432/!/; 操作,那麼這操作將賦予sql_mode什麼值呢?
mysql> SET @@session.sql_mode=1344274432;
Query OK, 0 rows affected (0.00 sec)
mysql> select @@global.sql_mode;
+--------------------------------------------+
| @@global.sql_mode |
+--------------------------------------------+
| NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION |
+--------------------------------------------+
1 row in set (0.00 sec)
mysql> select @@sql_mode;
+----------------------------------------------------------------+
| @@sql_mode |
+----------------------------------------------------------------+
| STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION |
+----------------------------------------------------------------+
1 row in set (0.00 sec)
執行操作之後,突然發現sql_mode多出來一個STRICT_TRANS_TABLES,這個時候大致可以獲取得到端倪了,因為在binlog在執行這條SQL的設定了session的sql_mode為嚴格模式,所以導致在sql_thread重放的時候出現了這個問題。
但是這個時候又冒出了一個新的問題,因為線上的表結構和架構和測試環境一模一樣,並且線上運行了這麼久的時間也沒有出現這個問題,帶著這個疑問我再次解析了線上binlog的日誌資訊:
#181101 10:12:26 server id 5403005 end_log_pos 420 CRC32 0x2fe38b78 Query thread_id=51519927 exec_time=0 error_code=0
SET TIMESTAMP=1541038346/*!*/;
SET @@session.pseudo_thread_id=51519927/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET @@session.sql_mode=1344274432/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8mb4 *//*!*/;
SET @@session.character_set_client=45,@@session.collation_connection=45,@@session.collation_server=45/*!*/;
SET @@session.time_zone='SYSTEM'/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
BEGIN
/*!*/;
# at 420
#181101 10:12:26 server id 5403005 end_log_pos 538 CRC32 0xb848f658 Table_map: `finance_fixin_cgb_gateway`.`t_cgb_receive_message` mapped to number 2056756
# at 538
#181101 10:12:26 server id 5403005 end_log_pos 740 CRC32 0x42756468 Write_rows: table id 2056756 flags: STMT_END_F
### INSERT INTO
### SET
### @1=5300431
### @2='PA0052'
### @3='b0009201811010033433728'
### @4='10.201.5.129'
### @5=2433
### @6='128'
### @7='0009a201811010143659612590571520'
### @8='000920180907OR23805082566791168'
### @9='0'
### @10='0000'
### @11='0000-操作成功。'
### @12='2018-11-01 10:12:26'
### @13='2018-11-01 10:12:26'
# at 740
#181101 10:12:26 server id 5403005 end_log_pos 771 CRC32 0xf5516de4 Xid = 12837058229
COMMIT/*!*/;
對比之後發現,線上的binlog格式是ROW格式,並且通過檢視insert語句發現在insert插入的時候沒有預設值會預設設定為' ',所以slave是不會報錯的。
解決問題
這個時候提出了倆個方案:
- 更改表結構,允許為NULL
- 設定master的binlog為ROW格式
最後和開發溝通之後還是選擇了第一個方案,修改表結構,主要是binlog格式的修改,必須先要斷開所有的連結,所以綜合考慮直接修改了表結構。
補充:
在binlog為statement的時候解析了發現了一條SET TIMESTAMP=1539922380語句,之前一直認為在statement格式下面使用時間函式會導致主從資料不一致,現在看到這個SQL,發現並不出現這種情況。