Laravel执行migrate:fresh --seed触发12815段错误问题排查
触发原因
- 核心诱因是PHP
pdo_sqlsrv扩展与SQL Server 2017的已知兼容bug:5.9.x、5.10.x版本的pdo_sqlsrv扩展在执行删库、批量删表操作时,处理SQL Server返回的TDS协议包会触发空指针内存访问,直接导致PHP进程段错误coredump,和Laravel框架逻辑无关。 - 旧环境重建数据库后能暂时恢复,是因为首次迁移没有执行删除已有库、已有表的逻辑,不会触发扩展的bug分支;新环境重建库仍报错,通常是两个原因:一是新环境安装的pdo_sqlsrv版本刚好命中bug触发条件,二是新环境CLI模式下开启了OPcache、或者SQL Server残留了孤立外键元数据,进一步放大了bug触发概率,从偶发变成必现。
- 次要触发场景:SQL Server 2017初始RTM版本(即
mcr.microsoft.com/mssql/server:2017-latest默认拉取的早期版本)存在系统表元数据返回异常,当migrate:fresh查询外键约束时,异常元数据会导致pdo_sqlsrv读取内存越界触发段错误。
永久修复方案
- 固定pdo_sqlsrv扩展版本:卸载当前已安装的sqlsrv、pdo_sqlsrv扩展,根据PHP版本安装兼容的无bug版本:
- PHP 7.4 ~ 8.1 环境:安装5.8.1稳定版
- PHP 8.2 及以上环境:安装5.11.1及以上版本
安装完成后执行php --ri pdo_sqlsrv确认版本,重启对应的PHP进程即可生效。
- 升级SQL Server 2017补丁:不要使用默认的2017-latest标签镜像,替换为打了CU31及以上累积更新的2017版本,修复TDS协议返回异常的底层问题。
- 修正Laravel数据库配置:打开
config/database.php,找到sqlsrv连接配置,显式设置'encrypt' => false,如果必须开启加密连接则正确配置SSL证书路径,避免握手阶段异常诱发扩展内存错误。
临时规避方法(无需升级组件时使用)
- 拆分
migrate:fresh执行逻辑,避开扩展触发bug的删库流程:
# 先通过tinker手动完成删库建库 php artisan tinker --execute="DB::statement('DROP DATABASE IF EXISTS 你的数据库名; CREATE DATABASE 你的数据库名;')" # 再单独执行迁移和数据填充,此时没有删表/删库操作不会触发段错误 php artisan migrate --seed
- 执行命令时临时关闭CLI模式的OPcache,避免缓存异常触发bug:
php -d opcache.enable_cli=0 artisan migrate:fresh --seed
- 本地开发场景可以临时切换为SQLite驱动做迁移测试,绕过pdo_sqlsrv扩展的兼容问题。
内容的提问来源于stack exchange,提问作者Pathros
相关产品推荐
相关产品推荐

