发布于2026-07-15 阅读(0)
扫一扫,手机访问
说到ThinkPHP 5.1的数据库配置,很多开发者其实都踩过同样的坑——明明改了个type值,结果要么连不上库,要么中文全变问号,更诡异的是SQL报错连个提示都没有。这些问题的根子,往往不在框架本身,而在于从旧版习惯切换到PDO驱动时,初始化参数那一环没对齐。
这里先把几个容易出问题的关键点拎出来:DSN里字符集必须写死、params参数要主动声明、驱动类型不能想当然地写mysqlnd。下面一条条拆开说。
先确认环境是否真的支撑PDO以及对应的数据库驱动。跑一下php -r "print_r(PDO::getA vailableDrivers());",输出数组里必须能看到【mysql】或【pdo_mysql】——二者有一个就算过关,但一个都没有的话,说明pdo_mysql.so压根没加载,或者php.ini里extension=pdo_mysql.so被注释掉了。Windows用户记得同时打开extension=php_pdo.dll和extension=php_pdo_mysql.dll,顺序还不能搞反。
TP5.1不再像老版本那样自动拼接字符集参数。光在params里写一句SET NAMES,根本覆盖不了连接建立时的字符集协商环节。正确的做法是在config/database.php的return数组中,把dsn写成完整字符串:
'dsn' => 'mysql:host=127.0.0.1;dbname=your_db;charset=utf8mb4;';
【charset=utf8mb4必须写在dsn里,不能只靠params来补】。如果漏了这步,后果就是emoji插入被截断、JSON字段解析失败、中文变成问号——而且错误根本不会报出来,查询要么返回空,要么字段值被静默丢弃,排查起来很折磨人。
ThinkPHP会把params原样透传给new PDO()的构造函数。你不配,它就按PHP的默认行为来,但默认行为在真实生产环境里基本等于埋雷:
① 加上 PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION —— 不加的话,SQL错误(比如字段名写错、权限不够)只会默默返回false或空数组,debug的时候你完全不知道错在哪一步;
② 加上 PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8mb4' —— 这是连接建立后再补一道字符集声明,跟dsn里的charset形成双重保险;
③ 加上 PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC —— 确保fetch()返回关联数组,避免字段顺序一变,索引取值就全乱套;
④ 开发环境强烈建议设 PDO::ATTR_PERSISTENT => false —— 连接复用可能干扰事务隔离,甚至导致未提交的数据残留。
操作方法有两种。方法一:直接改type值。把'type' => 'mysql'改成'type' => 'pdo_mysql'。方法二(更推荐的做法):删掉'type'这一项,只保留完整dsn——'dsn' => 'mysql:host=...',框架会自动识别为pdo_mysql。
【千万不能写 'type' => 'mysqlnd'】——这个驱动名在PHP 8.2以上版本已经被彻底移除。写了它,系统会直接报错"Driver [mysqlnd] not supported",而且不会告诉你具体是哪个配置项出了问题。
PHP 8.2已经彻底删掉了mysql_connect()这类老函数。哪怕整个项目里只残留了一处调用,应用启动就会直接fatal error。建议全局搜一下:grep -r "mysql_" app/ extend/ common/。重点翻翻历史插件、自定义数据库封装类、旧版支付SDK或者手写的DAO层。一旦发现类似mysql_query("SELECT ...")的调用,一律替换成think\Db::query("SELECT ...")。
如果搜索结果为空,也别觉得万事大吉——还得检查composer require进来的第三方包是否藏了mysql_*调用。某些老版本的think-queue或alipay-sdk-php,确实还遗留了这类问题。
