问题描述
公司项目使用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
才能避免这种问题。