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

Laravel 10 迁移日志增强需求:补充执行时间与SQL语句记录

Laravel 10 迁移额外日志实现方案

需求1:记录迁移执行时间(为migrations表添加created_at字段)

默认migrations表仅记录迁移文件名和批次,无执行时间信息。可通过以下步骤添加created_at字段:

  1. 创建新迁移文件:
php artisan make:migration add_created_at_to_migrations_table
  1. 编写迁移逻辑:
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    public function up(): void
    {
        Schema::table('migrations', function (Blueprint $table) {
            // 添加created_at字段,默认值为当前时间,兼容旧迁移记录
            $table->timestamp('created_at')->useCurrent()->nullable();
        });
        
        // 可选:为旧迁移记录批量填充created_at值
        \Illuminate\Support\Facades\DB::table('migrations')
            ->whereNull('created_at')
            ->update(['created_at' => now()]);
    }

    public function down(): void
    {
        Schema::table('migrations', function (Blueprint $table) {
            $table->dropColumn('created_at');
        });
    }
};
  1. 执行迁移:
php artisan migrate

需求2:记录实际SQL语句及受影响行数

--pretend参数无法保留占位符的实际值,因此需要手动捕获执行的SQL和受影响行数,建议创建专门的日志表存储信息:

步骤1:创建迁移日志表

生成创建migration_logs表的迁移:

php artisan make:migration create_migration_logs_table

编写迁移逻辑:

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    public function up(): void
    {
        Schema::create('migration_logs', function (Blueprint $table) {
            $table->id();
            // 关联migrations表的记录ID
            $table->foreignId('migration_id')->constrained()->onDelete('cascade');
            // 存储完整可执行的SQL语句
            $table->text('sql_statement');
            // 记录操作影响的数据行数
            $table->integer('affected_rows')->default(0);
            $table->timestamps();
        });
    }

    public function down(): void
    {
        Schema::dropIfExists('migration_logs');
    }
};

执行该迁移:

php artisan migrate

步骤2:在自定义迁移中添加日志记录逻辑

在需要记录SQL的迁移类中,手动捕获操作的SQL和受影响行数,写入日志表。示例如下:

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
use App\Models\Post;

return new class extends Migration
{
    public function up(): void
    {
        // 1. 定义查询并捕获基础信息
        $query = Post::where('id', '<', 1000);
        $rawSql = $query->toSql();
        $bindings = $query->getBindings();
        
        // 替换占位符为实际值,生成完整SQL
        $fullSql = str_replace('?', '%s', $rawSql);
        $fullSql = vsprintf($fullSql, array_map(function ($binding) {
            return is_string($binding) ? "'" . addslashes($binding) . "'" : $binding;
        }, $bindings));
        
        // 执行操作并获取受影响行数
        $affectedRows = $query->delete();

        // 2. 获取当前迁移记录的ID
        $currentMigration = DB::table('migrations')
            ->where('migration', class_basename($this))
            ->latest()
            ->first();

        // 3. 写入日志表
        DB::table('migration_logs')->insert([
            'migration_id' => $currentMigration->id,
            'sql_statement' => $fullSql,
            'affected_rows' => $affectedRows,
            'created_at' => now(),
            'updated_at' => now(),
        ]);
    }

    public function down(): void
    {
        // 回滚操作时可复用相同逻辑记录日志
        $query = Post::onlyTrashed()->where('id', '<', 1000);
        $rawSql = $query->toSql();
        $bindings = $query->getBindings();
        
        $fullSql = str_replace('?', '%s', $rawSql);
        $fullSql = vsprintf($fullSql, array_map(function ($binding) {
            return is_string($binding) ? "'" . addslashes($binding) . "'" : $binding;
        }, $bindings));
        
        $affectedRows = $query->restore();

        $currentMigration = DB::table('migrations')
            ->where('migration', class_basename($this))
            ->latest()
            ->first();

        DB::table('migration_logs')->insert([
            'migration_id' => $currentMigration->id,
            'sql_statement' => $fullSql,
            'affected_rows' => $affectedRows,
            'created_at' => now(),
            'updated_at' => now(),
        ]);
    }
};

批量操作的简化日志记录

如果迁移中有多个数据库操作,可封装辅助函数简化代码:

private function logMigrationQuery($query, $migrationId)
{
    $rawSql = $query->toSql();
    $bindings = $query->getBindings();
    
    $fullSql = str_replace('?', '%s', $rawSql);
    $fullSql = vsprintf($fullSql, array_map(function ($binding) {
        return is_string($binding) ? "'" . addslashes($binding) . "'" : $binding;
    }, $bindings));
    
    // 根据操作类型调整获取受影响行数的方式
    $affectedRows = method_exists($query, 'delete') ? $query->delete() : $query->update([]);

    DB::table('migration_logs')->insert([
        'migration_id' => $migrationId,
        'sql_statement' => $fullSql,
        'affected_rows' => $affectedRows,
        'created_at' => now(),
        'updated_at' => now(),
    ]);
}

在迁移的up方法中调用:

public function up(): void
{
    $currentMigration = DB::table('migrations')
        ->where('migration', class_basename($this))
        ->latest()
        ->first();
    $migrationId = $currentMigration->id;

    // 操作1:删除指定Post
    $this->logMigrationQuery(Post::where('id', '<', 1000), $migrationId);

    // 操作2:更新指定User状态
    $this->logMigrationQuery(User::where('status', 'inactive')->update(['status' => 'archived']), $migrationId);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 20:50:13