问题描述
主机:linux 5.8
Mysql版本:mysql-5.0.77
主库正常运行,但是从库却有如下报错:
Last_Error: Error 'Duplicate entry '2147483647' for key 2' on query. Default database: 'carddb'. Query: 'insert into USER_SESSION_LOG(USER_ID,SESSION_ID,CREATE_AT,IP) values(0x353334323431,0x4546323743353646314645433745384343453333433141373739444136463530,0x323031352D30362D31322032313A34363A3432,0x3131342E3234382E33362E323436)'
该表的表结构如下(主从一致):
show create table USER_SESSION_LOG\G
*************************** 1. row ***************************
Table: USER_SESSION_LOG
Create Table: CREATE TABLE `user_session_log` (
`ID` int(11) NOT NULL auto_increment,
`USER_ID` int(11) default NULL,
`SESSION_ID` varchar(32) character set gbk default NULL,
`CREATE_AT` datetime default NULL,
`IP` varchar(20) character set gbk default NULL,
PRIMARY KEY (`ID`),
UNIQUE KEY `userid` (`USER_ID`)
) ENGINE=MyISAM AUTO_INCREMENT=101234 DEFAULT CHARSET=latin1
报错的直接原因是因为第二列的值有重复了,并且值为'2147483647'(int类型最大值),查看主库中并没有这个值的出现。总结起来差不多有三个问题:
一:为什么会出现重复的值
二:0x353334323431该值远超过int类型最大值,binlog中为什么会有这个值
三:为什么只有个别的几张表在binlog中是已16进制体现的。
下面分别来看一下
1、 为什么会出现重复的值
下面做一个简单的测试:
1、 创建测试表test
mysql> create table test (id int(4) primary key, user_id int(11) unique);
Query OK, 0 rows affected (0.01 sec)
2、 插入一条正常数据。
mysql> insert into test values(1,2);
Query OK, 1 row affected (0.01 sec)
mysql> select * from test;
+------+--------------+
| id | user_id |
+------+--------------+
| 1 | 2 |
+------+--------------+
1 row in set (0.00 sec)
3、 以16进制方式插入数据
mysql> insert into test values(2,0x333732313431);
Query OK, 1 row affected, 1 warning (0.00 sec)
mysql> select * from test;
+----+---------------------+
| id | user_id |
+----+---------------------+
| 1 | 2 |
| 2 | 2147483647 |
+----+-------------------+
2 rows in set (0.00 sec)
可以看到插入确实没问题,但是依然插入进去了。
4、 再来
mysql> insert into test values(3,0x313338303931);
ERROR 1062 (23000): Duplicate entry '2147483647' for key 'user_id'
同样的错误。
从以上试验中得出mysql在插入int类型的值时,如果该值超过了int类型的最大值则以int类型的最大值进行插入,并出现warning,但不会出现error。这样以来当出现两个都大于int类型最大值的数据插入时,就会插入两条2147483647,从而引起唯一键冲突。
2、 0x353334323431该值远超过int类型最大值,binlog中为什么会有这个值
1、查看主库对应数据的值分别为
字段值(int) binlog(16进制)
138091 0x313338303931
372141 0x333732313431
很明显的可以看出16进制的数据远大于真实值,但是binlog中确实是这样体现的。
2、尝试转换16进制数据为字符串
SQL> select utl_raw.cast_to_varchar2('313338303931') from dual;
UTL_RAW.CAST_TO_VARCHAR2('313338303931')
--------------------------------------------------------------------------------
138091
SQL> select utl_raw.cast_to_varchar2('333732313431') from dual;
UTL_RAW.CAST_TO_VARCHAR2('333732313431')
--------------------------------------------------------------------------------
372141
转换成字符串以后竟然和原值是相同的。
以上可以知道,该16进制值是以字符串类型的值为基数进行转换的。
3、为什么只有个别的几张表在binlog中是已16进制体现的
查看主库binlog日志
SET TIMESTAMP=1434500837/*!*/;
/*!\C gbk *//*!*/;
SET @@session.character_set_client=28,@@session.collation_connection=28,@@session.collation_server=8/*!*/;
insert into USER_SESSION_LOG(USER_ID,SESSION_ID,CREATE_AT,IP) values(0x333732313431,0x4544463532363043444335434135314237463539353732423736464131393931,0x323031352D30362D31372030383A32373A3231,0x3231392E3233372E3133332E3232)【从库与主库一致】
ET TIMESTAMP=1434502429/*!*/;
SET @@session.sql_mode=2097152/*!*/;
/*!\C gbk *//*!*/;
SET @@session.character_set_client=28,@@session.collation_connection=28,@@session.collation_server=8/*!*/;
insert into g_ice_log (swap_type,market_code) values ('shops_page_activity_by_store','100050')
从日志中可以发现出问题表的值都是16进制显示,而其他表却正常显示字符串。
此问题主要与开发沟通,确认了问题表所在的应用,也确认了只有该应用所用的表有此问题。接下来对比了各应用连接mysql数据库的驱动,发现该应用所使用的驱动版本与其他应用有很大的跨度。通过与开发共同测试得出当mysql版本为5.0.77,mysql-connector 版本为3.1.12,并且字符集为gbk的时候就会出现此问题。而对于其他字符集,并未发现此问题。最终选择应用升级mysql-connector版本解决此问题。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/29621173/viewspace-1709387/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/29621173/viewspace-1709387/