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

警报响起:

               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

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









转载于:https://my.oschina.net/eric03/blog/410987

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
作为AI语言模型,我无法直接与数据库进行交互,但我可以提供一些思路: 1. 在HTML中通过JavaScript监听点击事件。 2. 在JavaScript中获取需要写入数据库数据。 3. 将获取到的数据通过AJAX发送给后端。 4. 后端接收到数据后,进行数据库操作,将数据写入数据库。 具体实现可以参考以下代码: HTML代码: ``` <button id="saveBtn">保存数据</button> ``` JavaScript代码: ``` document.getElementById("saveBtn").addEventListener("click", function() { // 获取需要写入数据库数据 var data = { name: "张三", age: 25, gender: "男" }; // 发送AJAX请求 var xhr = new XMLHttpRequest(); xhr.open("POST", "saveData.php", true); xhr.setRequestHeader("Content-Type", "application/json"); xhr.onreadystatechange = function() { if (xhr.readyState === 4 && xhr.status === 200) { console.log(xhr.responseText); } }; xhr.send(JSON.stringify(data)); }); ``` PHP代码: ``` <?php // 连接数据库 $pdo = new PDO("mysql:host=localhost;dbname=test", "root", "123456"); // 接收AJAX请求的数据 $data = json_decode(file_get_contents("php://input"), true); // 将数据写入数据库 $stmt = $pdo->prepare("INSERT INTO users (name, age, gender) VALUES (:name, :age, :gender)"); $stmt->bindParam(":name", $data["name"]); $stmt->bindParam(":age", $data["age"]); $stmt->bindParam(":gender", $data["gender"]); $stmt->execute(); // 返回操作结果 echo "数据保存成功"; ?> ``` 以上代码仅供参考,具体实现需要根据实际情况进行调整。同时,需要注意数据库操作的安全性和可靠性,避免出现数据泄露或数据损坏等问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值