本文目录导读:

在 PHP 中实现数据库迁移回滚,主要取决于你使用的迁移工具,以下是几种常见方式的详细说明:
使用 Laravel(最常用)
Laravel 内置了强大的迁移系统,支持回滚操作。
基础命令
# 回滚最后一次迁移 php artisan migrate:rollback # 回滚指定步数(回滚最后2次) php artisan migrate:rollback --step=2 # 回滚所有迁移 php artisan migrate:rollback --step=0 # 回滚并重新迁移(常用于开发环境) php artisan migrate:refresh # 回滚所有并重新迁移 php artisan migrate:fresh
定义可回滚的迁移
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateUsersTable extends Migration
{
/**
* 执行迁移
*/
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamps();
});
}
/**
* 回滚迁移(必须实现)
*/
public function down()
{
Schema::dropIfExists('users');
}
}
部分回滚
// 仅在特定条件满足时执行回滚
public function down()
{
if (Schema::hasTable('users')) {
Schema::table('users', function (Blueprint $table) {
// 只删除特定列
$table->dropColumn(['name']);
});
}
}
使用纯 PHP(手动实现)
如果不使用框架,可以自己实现简单的迁移回滚机制:
基础迁移类
<?php
interface MigrationInterface
{
public function up(PDO $pdo);
public function down(PDO $pdo);
}
abstract class BaseMigration implements MigrationInterface
{
protected $connection;
public function __construct(PDO $pdo)
{
$this->connection = $pdo;
}
protected function execute($sql)
{
try {
$this->connection->exec($sql);
echo "执行成功: " . date('Y-m-d H:i:s') . "\n";
} catch (PDOException $e) {
echo "执行失败: " . $e->getMessage() . "\n";
throw $e;
}
}
protected function log($message)
{
echo "[INFO] " . date('Y-m-d H:i:s') . " - " . $message . "\n";
}
}
具体迁移实现
<?php
class CreateUsersTableMigration extends BaseMigration
{
public function up(PDO $pdo)
{
$sql = "CREATE TABLE IF NOT EXISTS users (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4";
$this->execute($sql);
$this->log("用户表创建完成");
}
public function down(PDO $pdo)
{
$sql = "DROP TABLE IF EXISTS users";
$this->execute($sql);
$this->log("用户表已删除");
}
}
迁移管理器
<?php
class MigrationManager
{
private $pdo;
private $migrationsDir;
private $migrations = [];
public function __construct(PDO $pdo, $migrationsDir)
{
$this->pdo = $pdo;
$this->migrationsDir = $migrationsDir;
$this->ensureMigrationsTable();
$this->loadMigrations();
}
private function ensureMigrationsTable()
{
$sql = "CREATE TABLE IF NOT EXISTS migration_logs (
id INT PRIMARY KEY AUTO_INCREMENT,
migration_name VARCHAR(255) UNIQUE NOT NULL,
executed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)";
$this->pdo->exec($sql);
}
private function loadMigrations()
{
$files = glob($this->migrationsDir . '/*.php');
sort($files);
foreach ($files as $file) {
$className = basename($file, '.php');
require_once $file;
$this->migrations[$className] = new $className($this->pdo);
}
}
// 执行迁移
public function migrate()
{
foreach ($this->migrations as $name => $migration) {
// 检查是否已执行
$stmt = $this->pdo->prepare("SELECT id FROM migration_logs WHERE migration_name = ?");
$stmt->execute([$name]);
if (!$stmt->fetch()) {
echo "正在执行迁移: $name\n";
$migration->up($this->pdo);
// 记录执行日志
$stmt = $this->pdo->prepare("INSERT INTO migration_logs (migration_name) VALUES (?)");
$stmt->execute([$name]);
echo "迁移完成: $name\n";
}
}
}
// 回滚迁移
public function rollback($steps = 1)
{
// 获取最近执行的迁移
$stmt = $this->pdo->prepare(
"SELECT migration_name FROM migration_logs
ORDER BY id DESC LIMIT ?"
);
$stmt->execute([$steps]);
$executedMigrations = $stmt->fetchAll(PDO::FETCH_COLUMN);
foreach ($executedMigrations as $name) {
if (isset($this->migrations[$name])) {
echo "回滚迁移: $name\n";
$this->migrations[$name]->down($this->pdo);
// 删除迁移记录
$stmt = $this->pdo->prepare("DELETE FROM migration_logs WHERE migration_name = ?");
$stmt->execute([$name]);
echo "回滚完成: $name\n";
}
}
}
// 回滚所有
public function rollbackAll()
{
$stmt = $this->pdo->query("SELECT migration_name FROM migration_logs ORDER BY id DESC");
$executedMigrations = $stmt->fetchAll(PDO::FETCH_COLUMN);
foreach ($executedMigrations as $name) {
if (isset($this->migrations[$name])) {
echo "回滚迁移: $name\n";
$this->migrations[$name]->down($this->pdo);
$stmt = $this->pdo->prepare("DELETE FROM migration_logs WHERE migration_name = ?");
$stmt->execute([$name]);
echo "回滚完成: $name\n";
}
}
}
}
使用示例
<?php
// 连接数据库
$pdo = new PDO('mysql:host=localhost;dbname=my_database', 'username', 'password');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// 创建迁移管理器
$manager = new MigrationManager($pdo, __DIR__ . '/migrations');
// 执行迁移
$manager->migrate();
// 回滚最后一次迁移
$manager->rollback();
// 回滚最后3次迁移
$manager->rollback(3);
// 回滚所有迁移
$manager->rollbackAll();
使用第三方库
Doctrine Migrations
composer require doctrine/migrations
<?php
use Doctrine\Migrations\Configuration\Configuration;
use Doctrine\Migrations\DependencyFactory;
use Doctrine\Migrations\Configuration\Connection\ExistingConnection;
use Doctrine\Migrations\Configuration\Migration\PhpFile;
// 配置迁移
$config = new PhpFile('migrations.php');
$connection = new ExistingConnection($pdo);
$dependencyFactory = DependencyFactory::fromConnection($config, $connection);
// 回滚到指定的迁移版本
$dependencyFactory->getMigrator()->rollback('MigrationName');
// 回滚到上一个版本
$dependencyFactory->getMigrator()->rollback(['step' => 1]);
Phinx
composer require robmorgan/phinx
// 回滚命令 vendor/bin/phinx rollback vendor/bin/phinx rollback -t 20170310101000 // 回滚到指定版本
重要注意事项
- 总是实现
down()方法:每个迁移必须有对应的回滚逻辑 - 测试回滚:在生产环境执行回滚前,先在开发环境测试
- 备份数据:重要数据回滚前先备份
- 确保幂等性:回滚操作应该可以重复执行
- 处理复杂关系:考虑外键约束、索引等复杂关系
最佳实践
- 使用事务:在迁移和回滚中使用数据库事务
- 记录日志:记录所有迁移和回滚操作
- 版本控制:迁移文件提交到代码仓库
- 持续集成:在 CI/CD 流程中集成迁移测试
选择哪种方式取决于项目规模和需求,对于小型项目,手动实现足够;对于大型项目,建议使用 Laravel 或 Doctrine 等成熟方案。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播