1、簡單介紹該錯誤發生的背景:
1) 資料庫版本:MySQL5.7.19
2) 對一個大表修改字段類型DDL(将主鍵id int變為bigint),為了不影響主庫業務,先在從庫上執行DDL操作,然後通過主從切換完成最終的大表DDL;在從庫執行完DDL後,這時發現複制中斷了,報錯資訊:
1
2
Last_SQL_Errno: 1677
Last_SQL_Error: Column 0 of table 'darren.conversions' cannot be converted from type 'int' to type 'bigint(20)'
3)錯誤重制:
3
4
5
CREATE TABLE <code>conversions</code> (
<code>id</code> int(11) NOT NULL AUTO_INCREMENT,
<code>name</code> char(10) NOT NULL,
PRIMARY KEY (<code>id</code>)
) ENGINE=InnoDB
在從庫上,修改字段類型,将id int 變成bigint:
alter table conversions modify id bigint not null;
最後在主庫上向該表插入資料,這時從庫就報1677錯誤了。
2、解決方案
參考MySQL文檔中的方法,在從庫上設定slave_type_conversions ="ALL_NON_LOSSY",重新開機複制即可解決
MySQL> set global slave_type_conversions ='ALL_NON_LOSSY';
MySQL> stop slave;start slave;
3、關于該錯誤的詳細介紹
【不同資料類型的主從複制】:正常情況下,主庫和從庫每個表的各個列資料類型都是一緻的,但是MySQL并不強制這樣。有些特殊情況下,是存在主從列資料類型不一緻,比如上面的大表DDL操作,先在從庫上修改,然後切換主從,最後再修改老主庫的結構,當然,可能存在其他多種情況,不一一列舉。
【屬性更新和降級(attribute promotion and demotion)】:主從複制下,MySQL隻支援同類小資料類型和較大類型之間的屬性提升和降級,比如将主庫上int在從庫上轉為bigint,視為屬性更新,相反将bigint轉為int就是屬性降級。屬性升降級可用于基于語句和基于行的複制格式,并且不依賴于存儲引擎。但是,日志格式的選擇對允許的類型轉換有影響,這裡主要讨論row格式。
【有損和無損轉換(Lossy and non-lossy conversions)】:主從資料庫同一表同一列資料類型不一緻,會産生資料類型轉換。為了符合和适應目标列類型,截斷(或其他修改)源值,稱為有損轉換;不需要截斷或類似的修改以适應目标列中的源列值的轉換是一個非有損的轉換。這兩種轉換模式主要由slave_type_conversions系統變量控制,該變量的值如下:
Mode 影響描述
ALL_LOSSY(有損轉換) 該模式下,列類型轉換允許丢失一些資訊。如果隻設定該模式,隻允許同類的大資料類型轉換為小資料類型,其他模式的轉換都會發生1677錯誤。生産環境不建議設定該值,很容易導緻主從不一緻。
ALL_NON_LOSSY(無損轉換) 該模式下,不會導緻資料丢失和截斷,因為該值隻允許同類的小資料類型轉換為大資料類型,其他模式的轉換都會發生1677錯誤。生産環境建議設定該值
ALL_LOSSY,ALL_NON_LOSSY(兩種情況并存) 上面兩種模式都支援,生産環境不建議設定該值
[empty] (空值) 不設定任何值,表示不允許任何模式的類型轉換,如果發現類型轉換,都會産生1677錯誤,導緻複制中斷
4、測試
複制代碼
----------------------------------------當從庫修改為bigint----------------------------------------------------------------------------
mysql> show global variables like 'slave_type_conversions';
+------------------------+-----------+
| Variable_name | Value |
| slave_type_conversions | ALL_LOSSY |
1 row in set (0.00 sec)
mysql> show slave status\G
1. row
Last_Errno: 1677 #直接報錯了
Last_Error: Column 0 of table 'darren.conversions' cannot be converted from type 'int' to type 'bigint(20)'
----------------------------------------當從庫修改為tinyint----------------------------------------------------------------------------
master插入11111:
mysql> insert into conversions(id,name) values(11111,'a');
Query OK, 1 row affected (0.00 sec)
mysql>
mysql> select * from conversions;
+-------+------+
| id | name |
| 1 | a |
| 11111 | a |
slave的值127:
mysql> select * from darren.conversions;
+-----+------+
| id | name |
| 1 | a |
| 127 | a | #11111被截斷為127
4-2、slave_type_conversions='ALL_NON_LOSSY'
View Code
4-3、slave_type_conversions=''
5、支援哪些類型轉換?
【總結】設定空值是最嚴格的模式,不允許列類型不一緻,如果發生不一緻,從庫複制就中斷報錯了,能夠最大程度上維護主從資料一緻性。
如果日常運維,如大表DDL需要在從庫上進行的,可以先設定slave_type_conversions='ALL_NON_LOSSY',能夠保證從庫不會産生1677錯誤,但是對于整型字段,一定要注意主從unsigned或者signed問題,如果主庫signed,從庫上是unsigned,主從資料有可能不一緻;當主庫上unsigned,從庫signed的,一定要保證從庫字段足夠大能存下主庫字段值,否則也會導緻資料不一緻。
https://www.cnblogs.com/mysql-dba/p/8820798.html
參考文檔:https://dev.mysql.com/doc/refman/5.7/en/replication-features-differing-tables.html