标签搜索

PHP使用pdo查询MySQL数据库整型字段数据全部被转为字符型问题修复过程

basil
2021-05-20 / 285 阅读

问题描述

公司项目使用thinkphp5.1框架,在查询数据库获取数据时,整型字段的数据全部被转为字符型,根据网上查询的解决办法,将pdo属性这两项改为false仍然解决不了问题

ATTR_STRINGIFY_FETCHES
ATTR_EMULATE_PREPARES

产生原因

在stackoverflow.com上看到了相关的问题,点击查看,找到了原因
因为pdo_mysql扩展没有使用到mysqlnd驱动,所以就算关闭掉整型转换成字符型选项仍然不起效果。使用以下命令查看是否使用mysqlnd驱动:
使用mysqlnd时Client API version为mysqlnd:

    [root@iZ2vcfec25u9hyrvmipkttZ ~]# php --ri pdo_mysql
    
    pdo_mysql
    
    PDO Driver for MySQL => enabled
    Client API version => mysqlnd 5.0.12-dev - 20150407 - $Id: 7cc7cc96e675f6d72e5cf0f267f48e167c2abb23 $
    
    Directive => Local Value => Master Value
    pdo_mysql.default_socket => /tmp/mysql.sock => /tmp/mysql.sock

没有使用时,Client API version为5.5.65-MariaDB或者是其它:

    [root@boass-search-20200715 ~]# php --ri pdo_mysql
    
    pdo_mysql
    
    PDO Driver for MySQL => enabled
    Client API version => 5.5.65-MariaDB
    
    Directive => Local Value => Master Value
    pdo_mysql.default_socket => /var/lib/mysql/mysql.sock => /var/lib/mysql/mysql.sock



    [root@git-store-20200724 ~]# php --ri pdo_mysql
    
    pdo_mysql
    
    PDO Driver for MySQL => enabled
    Client API version => 5.6.37
    
    Directive => Local Value => Master Value
    pdo_mysql.default_socket => /var/lib/mysql/mysql.sock => /var/lib/mysql/mysql.sock

接着分析pdo_mysql没有使用到mysqlnd驱动的原因。公司生产环境使用的是php7.3.20版本,采用编译的方式进行安装,找到源代码目录config.log文件查看当初编译时的参数

    ./configure --prefix=/usr/local/php --with-zlib --enable-zip --with-openssl --enable-fpm --enable-mbstring --with-libdir=lib64 --with-curl --with-pdo-sqlite --with-mysqli=mysqlnd --with-gd --with-bz2 --enable-cli --enable-fileinfo --enable-session --enable-json --enable-libxml --with-libxml-dir --enable-xml --with-pear --with-jpeg-dir --with-pdo-mysql=/usr

发现了开启pdo_mysql扩展的编译参数为

--with-pdo-mysql=/usr

为了验证是否由于编译参数导致这个问题,临时租了一台与生产环境操作系统版本(centos)相同的服务器进行复现这个问题,同时下载php7.3.20版本源代码使用相同的编译参数进行编译。
编译过程中执行./configure时出现了以下错误

    configure: error: PDO_MYSQL configure failed, MySQL 4.1 needed. 

原因是采用--with-pdo_mysql=/usr这种方式编译PHP时,需要安装对应的mariab-devel或者mysql-devel才能进行编译,安装mariadb-devel后再次进行编译,编译安装完成后,查看pdo_mysql扩展是否使用mysqlnd

    [root@boass-search-20200715 php]# php --ri pdo_mysql
    
    pdo_mysql
    
    PDO Driver for MySQL => enabled
    Client API version => 5.5.65-MariaDB
    
    Directive => Local Value => Master Value
    pdo_mysql.default_socket => /var/lib/mysql/mysql.sock => /var/lib/mysql/mysql.sock

发现跟生产环境一样没有使用到mysqlnd驱动,使用pdo_mysql获取数据时会把整型字段数据转换为字符型,确认了是这种编译方式导致的问题。

解决办法

重新编译PHP,其它编译参数不变(可在config.log文件查看),将开启pdo_mysql扩展参数改为

    --with-pdo-mysql-mysqlnd

编译前需要执行

    make clean

不然编译将会报错,编译安装完成后,重启php-fpm,可看到pdo_mysql扩展使用mysqlnd驱动

    [root@iZ2vcfec25u9hyrvmipkttZ ~]# php --ri pdo_mysql
    
    pdo_mysql
    
    PDO Driver for MySQL => enabled
    Client API version => mysqlnd 5.0.12-dev - 20150407 - $Id: 7cc7cc96e675f6d72e5cf0f267f48e167c2abb23 $
    
    Directive => Local Value => Master Value
    pdo_mysql.default_socket => /tmp/mysql.sock => /tmp/mysql.sock

获取数据时也不会出现整型被转为字符型的问题

    {"id":10,"pid":1,"department":"??????","departcode":"STXSB","department_head":"580","status":0,"create_time":"2021-04-27 17:26:02"}
    array(7) {
      ["id"]=>
      int(11)
      ["pid"]=>
      int(1)
      ["department"]=>
      string(5) "?????"
      ["departcode"]=>
      string(5) "GCSYB"
      ["department_head"]=>
      string(10) "593,64,603"
      ["status"]=>
      int(0)
      ["create_time"]=>
      string(19) "2021-04-27 17:47:25"
    }

总结

因为编译PHP时,pdo_mysql扩展没有指定mysqlnd驱动,所以出现这个问题。编译时需要指定mysqlnd驱动

--with-pdo-mysql=mysqlnd

才能避免这种问题。

2