17370845950

php创建数据库怎么导入初始数据_php建库导数据法【步骤】
PHP中建库并导入SQL需分两步:先执行CREATE DATABASE(显式指定字符集),再重新连接该库;推荐用file_get_contents()+逐条mysqli_query()执行,避免multi_query缺陷,或用shell_exec("mysql")调用命令行工具,注意密码安全与错误检测。

用 mysqli 或 PDO 执行 CREATE DATABASE 后立刻导入 SQL 文件

PHP 本身不提供“一键建库+导入数据”函数,必须分两步:先建库,再连接该库并执行 SQL 语句。常见错误是建库后没切换数据库连接,导致 mysqli_query() 报错 No database selected

实操建议:

  • mysqli::query()PDO::exec() 执行 CREATE DATABASE `mydb` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci(显式指定字符集,避免后续乱码)
  • 建库成功后,**必须重新用新库名初始化连接**(PDO)或调用 mysqli_select_db()(mysqli),不能复用原连接
  • 读取 SQL 文件推荐用 file_get_contents() + mysqli_multi_query(),不要用 mysql_query()(已废弃)或逐行 explode(';', $sql)(会误切注释和字符串内的分号)

处理含多条语句的 SQL 文件时避免 mysqli_multi_query() 卡死

mysqli_multi_query() 虽支持批量执行,但不会自动跳过空行、注释或 DELIMITER 变更,遇到存储过程或触发器定义容易中断,且无法获取每条语句的错误详情。

更稳妥的做法是预处理 SQL 内容:

  • 用正则剔除 --/*...*/ 注释(注意避开字符串内出现的 --
  • ; 分割语句前,先用状态机跳过引号包裹的内容和括号嵌套(简单场景可用 preg_split('/;(?!.*[\'"])/', $sql) 粗略处理)
  • 对每条非空语句单独调用 mysqli_query(),便于定位哪句失败(例如建表语句里字段类型写成 INT(11) 在 MySQL 8.0.19+ 会警告但不报错,而 JSON 字段在旧版本直接报错)

shell_exec() 调用 mysql 命令行工具最省事但要注意权限和路径

绕过 PHP SQL 解析,直接走系统命令导入,适合大文件或含复杂语法的 SQL(如 LOAD DATA INFILE)。但必须确认:mysqld 进程允许本地 socket 连接、PHP 进程有权限读取 SQL 文件、mysql 命令在 PATH 中。

典型命令写法:

shell_exec("mysql -u root -prootpas

s -h 127.0.0.1 mydb < /path/to/init.sql 2>&1");

关键点:

  • 密码写在命令行里有泄露风险(ps aux 可见),应改用配置文件:mysql --defaults-extra-file=/tmp/my.cnf mydb ,其中 /tmp/my.cnf 权限设为 600
  • 如果 MySQL 配置了 skip-networking-h 127.0.0.1 会强制走 TCP,需改为 -S /var/run/mysqld/mysqld.sock 指定 socket 路径
  • 返回值为空不代表成功,要检查 shell_exec() 输出是否含 ERRORWarning 字样

初始化数据时外键约束和自增 ID 的坑

SQL 文件若含 INSERT INTO user VALUES (1,'a'),(2,'b'),而表已有数据,会导致主键冲突;若含 SET FOREIGN_KEY_CHECKS=0 但结尾没恢复,后续操作可能意外破坏参照完整性。

安全做法:

  • 导入前加 SET FOREIGN_KEY_CHECKS=0; SET UNIQUE_CHECKS=0; SET AUTOCOMMIT=0;,导入后补 SET FOREIGN_KEY_CHECKS=1; SET UNIQUE_CHECKS=1; COMMIT;
  • 对含自增字段的表,在 INSERT 前加 TRUNCATE TABLEDELETE FROM + ALTER TABLE ... AUTO_INCREMENT = 1,否则新数据 ID 可能从高位开始
  • 如果 SQL 文件由 mysqldump --no-create-info 生成,它默认不带 SET 语句,必须手动补全或用 --skip-extended-insert 避免单条语句过长触发 max_allowed_packet
实际部署时,CREATE DATABASE 和后续导入最好包在事务外——因为建库操作本身不能回滚,但数据导入失败时得能清理掉空库,这点容易被忽略。