pmatseykanets / laravel-sql-migrations
Laravel的原生SQL迁移
Requires
- php: ^7.2|^8.0.2
- laravel/framework: ~5.5|~6.0|~7.0|~8.0|~9.0
Requires (Dev)
- mockery/mockery: ^1.2.3
- phpunit/phpunit: ^8.3
This package is auto-updated.
Last update: 2024-09-06 10:58:59 UTC
README
使用纯SQL编写Laravel迁移。
如果你觉得这个包很有用,请考虑请我喝杯咖啡。
内容
原因
不要误会,Laravel的SchemaBuilder
绝对很棒,你可以从中获得很多好处。
但有时候它却成了绊脚石。以下是一些SchemaBuilder
力不从心的例子。
使用额外的/更丰富的数据类型
例如,如果你使用PostgreSQL并且想要为字符串/文本数据使用不区分大小写的数据类型,你可能可以考虑使用CITEXT
。这意味着我们必须求助于如下这种技巧
class CreateUsersTable extends Migration { public function up() { Schema::create('users', function (Blueprint $table) { $table->bigIncrement('id'); $table->string('email')->unique(); // ... }); DB::unprepared('ALTER TABLE users ALTER COLUMN email TYPE CITEXT'); } }
而不是简单地
CREATE TABLE IF NOT EXISTS users ( id BIGSERIAL PRIMARY KEY, email CITEXT UNIQUE, ... );
当然还有许多其他数据类型(例如,PostgreSQL中的范围或文本搜索数据类型)可能非常有用,但SchemaBuilder
却不知道,也不会知道。
管理存储函数、过程和触发器
这是一个很大的问题,尤其是如果你还在使用反向(down()
)迁移。这意味着你需要在迁移文件的up()
和down()
方法中同时包含函数/过程/触发器的新旧源代码,并将它们放在字符串变量中,这并不利于可读性和可维护性。
即使在php
中使用heredoc
/ nowdoc
语法,这仍然很糟糕。
利用IF [NOT] EXISTS
等语句
DDL语句中存在许多重要和有用的SQL标准兼容和供应商特定子句,可以让你生活更轻松。其中最著名和经常使用的是IF [NOT] EXISTS
。
而不是让ShemaBuilder
执行到information_schema
的单独查询
if (! Schema::hasTable('users')) { // create the table } if (! Schema::hasColumn('users', 'notes')) { // create the column }
你只需在一条语句中本地编写它
CREATE TABLE IF NOT EXISTS users (id BIGSERIAL PRIMARY KEY, ...); ALTER TABLE users ADD IF NOT EXISTS notes TEXT;
创建索引时使用额外选项
某些数据库(例如PostgreSQL)允许你在不锁定表的情况下(重新)创建索引。
CREATE INDEX CONCURRENTLY IF NOT EXISTS some_big_table_important_column_id ON some_big_table (important_column); CREATE INDEX IF NOT EXISTS table_json_column_idx USING GIN ON table (json_column);
你可能需要创建特定类型的索引而不是默认的btree
CREATE INDEX IF NOT EXISTS some_table_json_column_idx ON some_table (json_column) USING GIN;
或创建部分/函数索引
CREATE INDEX IF NOT EXISTS some_table_nullable_column_idx ON some_table (nullable_column) WHERE nullable_column IS NOT NULL;
利用数据库本地的过程代码(例如PL/pgSQL)
当使用PostgreSQL时,如果你需要,可以使用匿名PL/pgSQL代码块。例如,动态(在不提前知道数据库名的情况下)设置search_path
,如果你想在一个专门的架构中安装所有扩展而不是污染public
。
迁移文件.up.sql
可能看起来像这样
DO $$ BEGIN EXECUTE 'ALTER DATABASE ' || current_database() || ' SET search_path TO "$user",public,extensions'; END; $$;
以及反向的.down.sql
DO $$ BEGIN EXECUTE 'ALTER DATABASE ' || current_database() || ' SET search_path TO "$user",public'; END; $$;
安装
你可以通过composer安装这个包
composer require pmatseykanets/laravel-sql-migrations
如果你使用的是Laravel < 5.5或如果你已关闭包自动发现,你必须手动注册服务提供者
// config/app.php 'providers' => [ ... SqlMigrations\SqlMigrationsServiceProvider::class, ],
使用
制作SQL迁移
创建SQL迁移最方便的方式是使用带--sql
选项的artisan make:migration
命令
php artisan make:migration create_users_table --sql
这将生成三个文件
database └── migrations ├── 2018_06_15_000000_create_users_table.down.sql ├── 2018_06_15_000000_create_users_table.php └── 2018_06_15_000000_create_users_table.up.sql
我知道,这会增加migrations
目录中额外的文件,但这种方法允许您轻松混合使用传统和纯SQL迁移。如果您不使用反向(down
)迁移,只需删除*.down.sql
文件即可。
注意:如果您手动创建文件,请确保
- 基本
php
迁移类扩展了SqlMigration
类,并且不包含up()
和down()
方法,除非您打算重写默认行为。 .up.sql
和.down.sql
文件的名称(不包括扩展名)与基本php
迁移的文件名完全匹配(包括时间戳部分)。
到了这一步,您就可以忘记2018_06_15_000000_create_users_table.php
了,除非您想配置或重写此特定迁移的行为。
SqlMigration
扩展了内置的Migration
,因此您可以以相同的方式微调您的迁移。
class CreateNextIdFunction extends SqlMigration { // Use a non default connection public $connection = 'pgsql2'; // Wrap migration in a transaction if the database suports transactional DDL public $withinTransaction = true; }
现在,打开*.sql
文件并编写您的迁移代码。
例如,2018_06_15_000000_create_users_table.up.sql
可能看起来像这样
CREATE TABLE IF NOT EXISTS users ( id BIGSERIAL PRIMARY KEY, name CITEXT, email CITEXT, password TEXT, remember_token TEXT, created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP ); CREATE UNIQUE INDEX IF NOT EXISTS users_email_idx ON users (email);
和2018_06_15_000000_create_users_table.down.sql
DROP TABLE IF EXISTS users;
您还可以将--sql
选项传递给make:model
artisan命令,以指示它为您的全新模型创建纯SQL迁移。
php artisan make:model Post --migration --sql
运行SQL迁移
使用migrate
、migrate:rollback
和其他内置命令进行常规操作。
示例项目
您可以在以下位置找到带有默认SQL迁移的裸Laravel 5.6项目
变更日志
有关最近更改的更多信息,请参阅CHANGELOG
贡献
有关详细信息,请参阅CONTRIBUTING
致谢
许可
MIT许可(MIT)。有关更多信息,请参阅许可文件