文档章节

PDO写入十六进制数据导致数据库同步失败

Eric_chan
 Eric_chan
发布于 2015/05/05 18:17
字数 1171
阅读 27
收藏 0

警报响起:

               Last_SQL_Errno: 1062
               Last_SQL_Error: Error 'Duplicate entry '4294967295-2147483647-825241648' for key 'law_rea_pec'' on query. Default database: 'fuck_cn'. Query: 'INSERT INTO `u_law_pec` (`law_id`,`rea`,`pec`,`pec_sub`,`amount`,`stat`,`input_time`) VALUES (0x323036363434,0x323631333030,0x31303030,0x313030312C313030322C313030332C313030342C313030352C31303036,0x30,0x30,0x31343239383639323236)'

数据库同步挂了,整个体系瘫痪。

看到是有重复的值导致的,首先就跳过了一条记录。 再启动同步,可以同步了。ok

不一会 警报又响起了,还是一样的错误。

仔细一看 4294967295 已经是 int 无符号整形的最大值了。 INSERT语句里面还一堆的十六进制的字符串。

这个十六进制是怎么来的呢? 

如是查查日志,发现日志里面也是十六进制的,可以确认是PDO 连接类发过来的语句就是这样了。

首先是预处理,然后执行SQL语句,查询日志如下:

                Prepare INSERT INTO `u_law_pec` (`law_id`,`rea`,`pec`,`pec_sub`,`amount`,`stat`,`flag`,`input_time`) VALUES (?,?,?,?,?,?,?,?)
                Execute INSERT INTO `u_law_pec` (`law_id`,`rea`,`pec`,`pec_sub`,`amount`,`stat`,`flag`,`input_time`) VALUES (0x3330333034373335,0x313730333030,0x31323030,"",0x30,0x30,0x32,0x31343330383034343336)


通过这样去查看这些十六进制: 发现是可以正确解码的。

mysql> select 0x323036363434,0x323631333030,0x31303030,0x313030312C313030322C313030332C313030342C313030352C31303036,0x30,0x30,0x31343239383639323236;
+----------------+----------------+------------+--------------------------------------------------------------+------+------+------------------------+
| 0x323036363434 | 0x323631333030 | 0x31303030 | 0x313030312C313030322C313030332C313030342C313030352C31303036 | 0x30 | 0x30 | 0x31343239383639323236 |
+----------------+----------------+------------+--------------------------------------------------------------+------+------+------------------------+
| 206644         | 261300         | 1000       | 1001,1002,1003,1004,1005,1006                                | 0    | 0    | 1429869226             |
+----------------+----------------+------------+--------------------------------------------------------------+------+------+------------------------+

但是 INSERT 这个语句的时候发现写入的数据不对:

0x323036363434 对应的是 206644  却写入  4294967295

猜测是数据溢出了。  

0x323036363434 <16进制数值转10进制数值是>  55182649340980 远大于了INT 的最大值。

问题就在这里了:

  本来是需要十六进制转字符串文本的,结果mysql在这里把十六进制转成了十进制的数值。

因为表达式 x'test-string' (4.0 中新加入) 是基于 ANSI SQL 的,表达式 0x 是基于 ODBC 的, 所以我们没有使用ODBC的方式操作数据库的时候,就出现了上面的转储不正确的情况。


解决问题方法:

  1. PDO 传过来的数据用标准sql语句的文本格式,别搞些十六进制的字符串。

        通过对比实验发现 :

               Mysql5.6版本, PHP5.6 版本的 使用PDO 是不会出现上面的情况的。之前用的低版本的PHP带PDO 操作数据就会出现上面的问题。 所以 我们采用升级PHP版本的方式 解决这个问题。

--------------------------------------

今天发现之前也有路人甲遇到过此类问题并且分析的比较详细:

       访问 mysql server 的方式有两种。
       1、 直接访问模式
       2、 预处理模式
       先说说这两个结构的区别,直接访问就像我们用客户端连接进数据那样,标准的 sql 语句插入、更新、删除和查询。这个要求就是每个命令里面都要指明 表、字段、等信息。
       预处理就是:先告诉 mysql 一个表的结构,然后,后面的全都按照这个表结构来,这样就不用每次都发送 表、字段等信息了。这样的优势是大量的插入会快一点。特点是只在第一次发送表结构。而不是每次都发送一遍,问题是 mysql binlog 里面不支持这种格式。
       这两种方式比较起来,第一种 安全,第二种 快速 。第二种因为没有表结构,所以当任何一个字段出现问题,就会造成所有的数据问题,而不像第一种,只影响那一句。那个 PDO 使用的就是第二种方式,而且他错误的认为一切都是字符串,把所有的数据都转换成 16 进制了。
       在第一次插入的时候 mysql 使用第二种方式插入数据,但 binlog 里面因为没有这种结构,所以他自己把语句转换成了 第一种模式,加上了表、及字段信息,但 mysql 不会对 int 形做相应的转换,(这个在字符串表示中是没有错误的),造成了记录的日志是按照字符串的方式记录的。这样在吧一个字符串插入 int 形就出现了插入的数据和日志不一致的情况。要解决这个问题只有 1、给mysql 写一个补丁,解决这个问题。(现在功力不够还写不出来) 2、在我们公司禁用 预处理结构体方式的数据写入。看来目前我们只能使用第二种方法了。


       结论:
       总的来说,pdo 写的有问题,mysql 的 log 记录转换的方式也存在问题。下面是我写的一个能够触发这个 bug 的代码。

原文:http://blog.csdn.net/ugg/article/details/9042255

-------------------------------------------------









© 著作权归作者所有

共有 人打赏支持
Eric_chan
粉丝 0
博文 3
码字总数 1348
作品 0
广州
【原创】modb 中日志的设计

【日志格式】 在之前确定好通信所用的 json 数据格式后,到确定最终生成的日志内容的时候了。之前提到日志内容至少要包括下面几点: 日志记录的时间戳(在本地生成) 日志的“流向”(从哪里...

摩云飞
2014/01/23
115
0
【分布式】数据库和缓存双写一致性方案解析

引言 为什么写这篇文章? 首先,缓存由于其高并发和高性能的特性,已经在项目中被广泛使用。在读取缓存方面,大家没啥疑问,都是按照下图的流程来进行业务操作。 但是在更新缓存方面,对于更...

Java填坑之路
07/18
0
0
使用sqlmap对某php网站进行注入实战及安全防范

使用sqlmap对某php网站进行注入实战 一般来讲一旦网站存在sql注入漏洞,通过sql注入漏洞轻者可以获取数据,严重的将获取webshell以及服务器权限,但在实际漏洞利用和测试过程中,也可能因为服...

simeon2005
06/29
0
0
分布式数据库与缓存双写一致性方案解疑

作者介绍 孤独烟,中国平安研发工程师,目前负责规则云平台架构设计以及需求研发工作。毕业后一直从事Java开发工作,在Web开发、架构设计上有多年的实战经验。在MySQL性能优化、JVM调优、分布...

孤独烟
06/01
0
0
分布式之数据库和缓存双写一致性方案解析

原文出处:孤独烟 引言 为什么写这篇文章? 首先,缓存由于其高并发和高性能的特性,已经在项目中被广泛使用。在读取缓存方面,大家没啥疑问,都是按照下图的流程来进行业务操作。 但是在更新...

孤独烟
05/17
0
0

没有更多内容

加载失败,请刷新页面

加载更多

秒杀网站系统设计详解

最近总有一些朋友问高并发问题,后来就想自己把一个秒杀系统作为例子详细分解一下,也是一个学习过程。 首先假设场景,预计该活动可能有1万人参加,那最大并发数为1万。 主要面对的问题分析:...

小海bug
30分钟前
2
0
TypeScript基础入门之装饰器(一)

转发 TypeScript基础入门之装饰器(一) 介绍 随着TypeScript和ES6中Classes的引入,现在存在某些场景需要额外的功能来支持注释或修改类和类成员。 装饰器提供了一种为类声明和成员添加注释和元...

durban
40分钟前
1
0
sed命令扩展使用操作

打印某行到某行之间的内容 假若文件test.txt的内容是: ertfff**[abcfd]123324444[rty]**fgfgf 怎么能截取 [abcfd]123324444[rty] 这一部分出来呢? 操作命令: 知道开始行和结...

野雪球
55分钟前
1
0
JVM内存笔记

Hotspot JVM 中的 Java 线程与原生操作系统线程有直接的映射关系。当线程本地存储、缓 冲区分配、同步对象、栈、程序计数器等准备好以后,就会创建一个操作系统原生线程。 Java 线程结束,原...

凌渡
今天
1
0
284. Peeking Iterator

Description Tag: Design Difficulties: Medium Given an Iterator class interface with methods: next() and hasNext(), design and implement a PeekingIterator that support the pee......

52iSilence7
今天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部