You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel 10如何通过迁移自动创建PostgreSQL测试数据库?

Laravel通过主数据库连接创建PostgreSQL测试库的解决方案

问题描述

我正在为Laravel搭建环境,需要在一台PostgreSQL服务器上配置两个数据库:生产库名为laravel,测试/开发库名为laravel_test。尝试通过Laravel数据库迁移创建新数据库,使用了以下代码:

$dbName = config("database.connections.pgsql-test.database");
// Create the second database
DB::statement("CREATE DATABASE $dbName");

但出现错误:

SQLSTATE[25001]: Active sql transaction: 7 ERROR:  CREATE DATABASE cannot run inside a transaction block (Connection: pgsql, SQL: CREATE DATABASE laravel_test)

现有主数据库连接pgsql配置:

'pgsql' => [
     'driver' => 'pgsql',
     'url' => env('DATABASE_URL'),
     'host' => env('DB_HOST', '127.0.0.1'),
     'port' => env('DB_PORT', '5432'),
     'database' => env('DB_DATABASE', 'forge'),
     'username' => env('DB_USERNAME', 'forge'),
     'password' => env('DB_PASSWORD', ''),
     'charset' => 'utf8',
     'prefix' => '',
     'prefix_indexes' => true,
     'search_path' => 'public',
     'sslmode' => 'prefer',
],

测试库连接pgsql-test配置:

'pgsql-test' => [
     'driver' => 'pgsql',
     'url' => env('DATABASE_URL'),
     'host' => env('DB_HOST', '127.0.0.1'),
     'port' => env('DB_PORT', '5432'),
     'database' => env('DB_DATABASE', 'forge') . "_test",
     'username' => env('DB_USERNAME', 'forge'),
     'password' => env('DB_PASSWORD', ''),
     'charset' => 'utf8',
     'prefix' => '',
     'prefix_indexes' => true,
     'search_path' => 'public',
     'sslmode' => 'prefer',
],

能否通过主数据库连接创建新数据库,无需手动创建即可使用pgsql-test连接?

解决方案

核心问题原因

PostgreSQL的CREATE DATABASE命令不能在事务块内执行,而Laravel默认会为迁移操作开启事务,直接在迁移里执行这条语句就会触发错误。

实现步骤

  • 绕过事务执行创建命令
    利用Laravel的unprepared()方法绕过事务包装,直接通过主连接执行创建语句:

    $dbName = config("database.connections.pgsql-test.database");
    // 使用主连接执行无事务的SQL
    DB::connection('pgsql')->unprepared("CREATE DATABASE $dbName");
    
  • 先验证再创建,避免重复报错
    先查询数据库是否存在,不存在再执行创建:

    $dbName = config("database.connections.pgsql-test.database");
    $exists = DB::connection('pgsql')->select("SELECT 1 FROM pg_database WHERE datname = ?", [$dbName]);
    
    if (empty($exists)) {
        DB::connection('pgsql')->unprepared("CREATE DATABASE $dbName");
    }
    
  • 推荐:封装为Artisan命令
    创建自定义Artisan命令统一管理测试库创建逻辑,比如db:create-test:

    // app/Console/Commands/CreateTestDatabase.php
    namespace App\Console\Commands;
    
    use Illuminate\Console\Command;
    use Illuminate\Support\Facades\DB;
    
    class CreateTestDatabase extends Command
    {
        protected $signature = 'db:create-test';
        protected $description = '创建Laravel测试数据库';
    
        public function handle()
        {
            $dbName = config("database.connections.pgsql-test.database");
            $exists = DB::connection('pgsql')->select("SELECT 1 FROM pg_database WHERE datname = ?", [$dbName]);
    
            if (empty($exists)) {
                DB::connection('pgsql')->unprepared("CREATE DATABASE $dbName");
                $this->info("数据库 $dbName 创建成功!");
            } else {
                $this->info("数据库 $dbName 已存在。");
            }
        }
    }
    

    注册命令后,执行php artisan db:create-test即可完成测试库创建。

注意事项

  • 确保主连接的数据库用户拥有创建数据库的权限,否则会触发权限不足错误。
  • 不要在迁移文件中处理数据库创建逻辑,迁移的核心职责是管理表结构变更,数据库创建属于环境初始化操作。

内容的提问来源于stack exchange,提问作者Erikas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 01:43:18