【20181101】MySQL text類型的column設置爲NOT NULL 導致主從1364

環境

系統版本 : CentOS release 6.8 (Final)
MySQL版本:5.6.29-log MySQL Community Server (GPL)

MySQL主從配置信息

  1. binlog format :MIXED
  2. 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,這個時候我在自己本地執行這個insert 插入語句驗證是否可以插入成功,發現是可以插入的。

猜想

這個時候我就想這個是否在主從複製的過程中,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,發現並不出現這種情況。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章