slave报错信息如下:
[ERROR] Slave SQL: Error 'Incorrect string value: '\xB8\xD3M451...' for column 'car_reg_no' at row 1' on query. Default database: 'portal'. Query: 'INSERT INTO ei_case (case_id,car_reg_no) VALUES ( 4216530, 0xB8D34D3435313833)', Error_code: 1366
[Warning] Slave: Incorrect string value: '\xB8\xD3M451...' for column 'car_reg_no' at row 1 Error_code: 1366
[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.001243' position 157818406
Master中查询ei_case表中case_id 为123456的记录,返回正常。
mysql> SELECT case_id,car_reg_no FROM EI_CASE where case_id ='123456';
+---------+------------+
| case_id | car_reg_no |
+---------+------------+
| 123456 | 赣M45183 |
+---------+------------+
1 row in set
但这条记录复制到slave中就出错了,为什么呢?
[Warning] Slave: Incorrect string value: '\xB8\xD3M451...' for column 'car_reg_no' at row 1 Error_code: 1366
从这个Warning中我们可以看到是在对字段car_reg_no插入0xB8D34D3435313833时报错了。
那么0xB8D34D3435313833代表什么意思呢?
我们知道在master中case_id为123456对应的car_reg_no为赣M45183 。
先看一下赣M45183对应的16进制数是多少。
mysql> select hex('赣'), HEX('M45183') , HEX('赣M45183') from dual;
+-----------+---------------+--------------------+
| hex('赣') | HEX('M45183') | HEX('赣M45183') |
+-----------+---------------+--------------------+
| E8B5A3 | 4D3435313833 | E8B5A34D3435313833 |
+-----------+---------------+--------------------+
赣对应的16进制数是'E8B5A3',M45183对应的16进制数'4D3435313833'
'赣M45183' 对应的16进制数是'E8B5A34D3435313833'
而日志中显示的对car_reg_no插入的值是0xB8D34D3435313833。与我们分析的
赣M45183对应的16进制数是E8B5A34D3435313833 是不一致的。
那么0xB8D34D3435313833代表什么呢?
mysql> select unhex('E8B5A34D3435313833') ,unhex('B8D34D3435313833') from dual;
+-----------------------------+---------------------------+
| unhex('E8B5A34D3435313833') | unhex('B8D34D3435313833') |
+-----------------------------+---------------------------+
| 赣M45183 | ??M45183 |
+-----------------------------+---------------------------+
1 row in set
汉字'赣'显示为??,这个导致了slave中的插入失败。
为什么会导致这个问题呢?
检查了一下表中的数据car_reg_no有很包含'赣'的汉字都能正常插入.
如果是程序的问题,应该都插入失败,不应该只有个别的一两个包含'赣'的汉字插入失败,为什么呢?
想要找到问题的根源,首先要知道这个insert语句是从那发起的。
master上开启了binlog,找到对应的sql还是比较好容易的。
#mysqlbinlog mysql-bin.001241 |grep 'INSERT INTO ei_case' -a8
SET TIMESTAMP=1416470948/*!*/;
/*!\C gbk *//*!*/;
SET @@session.character_set_client=28,@@session.collation_connection=28,@@session.collation_server=8/*!*/;
BEGIN
/*!*/;
# at 157818477
#141120 16:09:08 server id 2253306 end_log_pos 157818841 Query thread_id=5745278 exec_time=0 error_code=0
SET TIMESTAMP=1416470948/*!*/;
INSERT INTO ei_case (case_id,car_reg_no) VALUES ( 4216530, 0xB8D34D3435313833)
/*!*/;
# at 157818841
#141120 16:09:08 server id 2253306 end_log_pos 157818868 Xid = 189237525811
COMMIT/*!*/;
# at 157818868
#141120 16:09:09 server id 2253306 end_log_pos 157818939 Query thread_id=5745260 exec_time=0 error_code=0
SET TIMESTAMP=1416470949/*!*/;
/*!\C utf8 *//*!*/;
在分析binlog的时候发现了一个问题/*!\C gbk *//*!*/;,而服务器上的字符集是utf8。
mysql> show variables like '%char%';
+--------------------------+--------------------------------------+
| Variable_name | Value |
+--------------------------+--------------------------------------+
| character_set_client | utf8 |
| character_set_connection | utf8 |
| character_set_database | utf8 |
| character_set_filesystem | binary |
| character_set_results | utf8 |
| character_set_server | latin1 |
| character_set_system | utf8 |
| character_sets_dir | /db/mysql5.5/share/charsets/ |
+--------------------------+--------------------------------------+
8 rows in set
怀疑是客户端在插入的时候使用了GBK字符集,插入到master中。
但插到slave中使用的是utf8的字符集,所以出错。
跟开发的同事沟通,开发的同事没有在程序中找到同样的SQL.
除了程序还有谁能修改数据库的记录呢?检查mysql的权限表,发现了一个自动上传数据的kettle用户。
检查kettle中的字符集设置果然为GBK。
问:为什么选择GBK字符集。
同事答:如果用UTF8插入中文乱码?
问:MySQL 的驱动是多少
答:mysql-connector-java-5.1.17.
我们用的myslq版本是5.5,mysql-connector-java-5.1.17这个驱动对UTF8字符集的支持不好。更换高版本的驱动后,改用UTF8字符集插入master和slave都正常。
至此,困扰几天的 Slave SQL: Error 'Incorrect string value Error_code: 1366 问题解决。