删掉 charset 参数才能连上 postgresql,因 tp8 将其原样塞入 pdo dsn,而 pdo_pgsql 驱动不识别该参数,导致连接静默失败、查询时抛空异常。

为什么删掉 charset 参数才能连上 PostgreSQL
ThinkPHP 8 把 charset 配置项原样塞进 PDO DSN,而 PostgreSQL 的 PDO 驱动根本不认这个参数。一写上就导致 PDO::__construct() 内部静默失败,不报具体错误,只在执行查询时抛出空 QueryException——连日志里都看不到真实原因。
- 错误表现:连接看似成功(
Db::connect()不报错),但第一次select()就崩,堆栈里没有 PostgreSQL 相关线索 - 验证方式:用
php -r "print_r(PDO::getAvailableDrivers());"确认pgsql在列表里;再检查database.php是否还留着'charset' => 'utf8' - 正确做法:直接从数据库配置数组中删掉整个
charset键,或显式设为null(TP8 遇到null会跳过拼接)
pdo_pgsql 扩展没启用,连错地方都找不到
TP8 的 PostgreSQL 支持完全依赖 PHP 底层的 pdo_pgsql 扩展,不是 Composer 装个包就能跑。扩展缺失时,哪怕 DSN 写对了、密码也对,PDO 构造器直接拒绝初始化,报错指向“driver not found”而非连接超时。
PHP 8.5.12 RC 1 候选版修复 BZ2、DOM、PDO、Opcache/JIT 和扩展内存安全问题,改进 Unicode 字素处理、URL 解析、TLS 流状态、信号分发及会话错误处理。
- Linux(Debian/Ubuntu):
sudo apt install php-pgsql,然后重启php-fpm或apache2 - Windows:检查
php.ini中这两行是否取消注释:extension=php_pdo_pgsql.dll和extension=php_pgsql.dll;若提示libpq.dll找不到,需在httpd.conf加LoadFile "C:/php/libpq.dll" - Docker 场景:不能只装扩展,还要确保容器内 hostname 是 PostgreSQL 服务名(如
pg),而不是127.0.0.1
软删除字段配置错一个字,delete() 就变物理删除
ThinkPHP 8 的软删除不是开个开关就行,它靠字段名精确匹配来决定走标记逻辑还是真删。模型里没声明 $deleteTime,或者数据库字段名和类型对不上,调用 delete() 会直接执行 DELETE FROM,且毫无提示。
- 必须显式写
protected $deleteTime = 'delete_time';,哪怕字段名就是默认值——TP8 不再自动 fallback - 字段类型要匹配:用
DATETIME NULL DEFAULT NULL最稳;若用INT,得加protected $type = ['delete_time' => 'integer'];,否则查询时whereNotNull('delete_time')永远不生效 - 别让
$autoWriteTimestamp = true污染该字段:新增记录时框架可能把delete_time写成0或空字符串,导致后续软删失效
批量删除用 destroy() 还是 Db::delete()
批量删数据时,UserModel::destroy([1,2,3]) 看起来简洁,但它会逐条查出再调 delete(),触发模型事件和软删除逻辑;而 Db::name('user')->where('id', 'in', [1,2,3])->delete() 是一条 SQL 干掉,快但绕过所有模型层。
- 要软删除 + 事件:用
destroy(),但注意它不支持复杂条件(比如where('status', 0)),只能传 ID 列表或主键条件 - 要速度 + 复杂条件:用
Db::delete(),但得自己处理软删除字段更新(比如手动setInc('delete_time', time())) - 大数据量(>1000 行):必须分批,
destroy()默认不限制,一次拉全量进内存可能 OOM
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!










