Slave SQL: Error 'Incorrect string value ... Error_code: 1366


背景:

主從環境一樣,字符集是utf8。

Slave復制報錯,平時復制都正常也沒有出現過問題,今天突然報錯:

150610 17:47:10 [ERROR] Slave SQL: Error 'Incorrect string value: '\xD3\xC3\xB6\xD2\xBB\xBB...' for column 'remark' at row 1' on query. Default database: 'jj'. Query: 'INSERT INTO user_book(appType,bookId,createTime,deviceType,id,modifyTime,money,remark,status,userId) VALUES (1,8004453,'2015-06-10 17:06:10',0,0,'2015-06-10 17:06:10',600,0xCAB9D3C3B6D2BBBBC2EB20454E4547435056505452555020B9BAC2F2,1,4669278)', Error_code: 1366
150610 17:47:10 [Warning] Slave: Incorrect string value: '\xD3\xC3\xB6\xD2\xBB\xBB...' for column 'remark' at row 1 Error_code: 1366
150610 17:47:10 [ERROR] Error running query, slave SQL thread aborted. Fix the problem, and restart the slave SQL thread with "SLAVE START". We stopped at log 'mysql-bin-3306.003582' position 207897687

perror 1366

MySQL error code 1366 (ER_TRUNCATED_WRONG_VALUE_FOR_FIELD): Incorrect %-.32s value: '%-.128s' for column '%.192s' at row %ld

從上面2個信息得到從庫復制失敗的原因是因為字符集的問題引起的。

分析:

在Master上查詢該條記錄,看看是否正常:

>select remark from user_book where appType=1 and bookId=8004453 and createTime='2015-06-10 17:06:10';
+-------------------------------------+
| remark                              |
+-------------------------------------+
| 使用兌換碼 ENEGCPVPTRUP 購買        |
+-------------------------------------+

在主上寫入正常,但在從上寫入就報錯了,為什么?

 [Warning] Slave: Incorrect string value: '\xD3\xC3\xB6\xD2\xBB\xBB...' for column 'remark' at row 1 Error_code: 1366

在錯誤日志里面看到從上對應插入的語句是:

INSERT INTO user_book(appType,bookId,createTime,deviceType,id,modifyTime,money,remark,status,userId) VALUES (1,8004453,'2015-06-10 17:06:10',0,0,'2015-06-10 17:06:10',600,0xCAB9D3C3B6D2BBBBC2EB20454E4547435056505452555020B9BAC2F2,1,4669278)

這里的"0xCAB9D3C3B6D2BBBBC2EB20454E4547435056505452555020B9BAC2F2"代表什么意思呢?因為在主上看到的值是"使用兌換碼 ENEGCPVPTRUP 購買"。那么看下他的16進制數是多少:

主:
>select hex('使用兌換碼'),hex('ENEGCPVPTRUP'),hex('購買'),hex('使用兌換碼 ENEGCPVPTRUP 購買')
    -> ;
+--------------------------------+--------------------------+---------------+------------------------------------------------------------------------+
| hex('使用兌換碼')              | hex('ENEGCPVPTRUP')      | hex('購買')   | hex('使用兌換碼 ENEGCPVPTRUP 購買')                                    |
+--------------------------------+--------------------------+---------------+------------------------------------------------------------------------+
| E4BDBFE794A8E58591E68DA2E7A081 | 454E45474350565054525550 | E8B4ADE4B9B0  | E4BDBFE794A8E58591E68DA2E7A08120454E4547435056505452555020E8B4ADE4B9B0 |
+--------------------------------+--------------------------+---------------+------------------------------------------------------------------------+

看到主上的值轉換出來之后和從上的不一致,這個就是這次問題的所在,那么通過unhex來看看從上的到底是什么導致插入錯誤的。

主:E4BDBFE794A8E58591E68DA2E7A08120 454E4547435056505452555020 E8B4ADE4B9B0
從:CAB9D3C3B6D2BBBBC2EB20 454E4547435056505452555020 B9BAC2F2

上面看到對於英文是沒有問題的,字符集問題主要出在漢字上面。通過unhex查看:

主:
>select unhex('E4BDBFE794A8E58591E68DA2E7A08120'),unhex('454E4547435056505452555020'),unhex('E8B4ADE4B9B0');
+-------------------------------------------+-------------------------------------+-----------------------+
| unhex('E4BDBFE794A8E58591E68DA2E7A08120') | unhex('454E4547435056505452555020') | unhex('E8B4ADE4B9B0') |
+-------------------------------------------+-------------------------------------+-----------------------+
| 使用兌換碼                                | ENEGCPVPTRUP                        | 購買                  |
+-------------------------------------------+-------------------------------------+-----------------------+

從:
>select unhex('CAB9D3C3B6D2BBBBC2EB20'),unhex('454E4547435056505452555020'),unhex('B9BAC2F2');
+---------------------------------+-------------------------------------+-------------------+
| unhex('CAB9D3C3B6D2BBBBC2EB20') | unhex('454E4547435056505452555020') | unhex('B9BAC2F2') |
+---------------------------------+-------------------------------------+-------------------+
| ʹ?öһ???                             | ENEGCPVPTRUP                        | ????                  |
+---------------------------------+-------------------------------------+-------------------+

上面得出的結果是確實存在亂碼導致插入異常。理論上來說主上執行什么,從上就應該執行什么,不會出現問題,那這次錯誤是怎么回事?

主從上表結構都是一樣的,主從表的remark字段的字符集是utf8,並且從在MySQL客戶端上也可以正常插入中文,為什么通過復制存就出問題了?所以亂碼和表字符集沒有關系。如果是程序問題,那主從應該都會出錯。所以和程序也沒有關系,那到底和什么有關系?

在主上的binlog查看那條插入語句:

/*!\C gbk *//*!*/; SET @@session.character_set_client=28,@@session.collation_connection=28,@@session.collation_server=33/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
BEGIN
/*!*/;
# at 207897755
#150610 17:06:10 server id 3  end_log_pos 207897783     Intvar  
SET INSERT_ID=47282/*!*/;
# at 207897783
#150610 17:06:10 server id 3  end_log_pos 207898096     Query   thread_id=3945271       exec_time=0     error_code=0
use `jj`/*!*/;
SET TIMESTAMP=1433927170/*!*/;
INSERT INTO user_book(appType,bookId,createTime,deviceType,id,modifyTime,money,remark,status,userId) VALUES (1,8004453,'2015-06-10 17:06:10',0,0,'2015-06-10 17:06:10',600,0xCAB9D3C3B6D2BBBBC2EB20454E4547435056505452555020B9BAC2F2,1,4669278)
/*!*/;

這里需要注意:在上面紅色加粗的地方看到插入的時候默認字符集是gbk,而整個數據庫的字符集也是gbk,程序客戶端寫入也是gbk。但是數據表的remark字段的字符集是utf8的。在主的寫入時,utf8可以包含gbk的編碼,進行內部轉換,所以主寫入是沒有問題的。但是從庫的SQL線程在執行時候就報錯,說明問題可以定位到從庫在執行的時候報錯。

說到這里,有個問題是為什么binlog記錄的是十六進制,而不是正常的?問題就出在這里,具體的分析見:http://backend.blog.163.com/blog/static/20229412620133274030845/

那為什么之前復制沒有問題,而現在復制出現了問題。原因是之前這個字段的寫入都是非中文的字符串,現在有中文寫入,錯誤就來了。

解決:

把沒有寫入的數據補到從上去,並且把主從數據庫表的remark字段都設置成gbk,問題解決。另一個方法就是把binlog format設置成Row。

 

總結:

上面的問題說明,對MySQL進行操作的時候一定要注意字符集編碼的問題,最好讓客戶端、服務端、表、字段的字符集保持一致。不一致導致的亂碼問題是比較常見的一種錯誤。

 

相關文章

http://blog.csdn.net/lwei_998/article/details/41346655

http://www.cnblogs.com/zhoujinyi/archive/2012/11/01/2748313.html


免責聲明!

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



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