Swoft2 框架精华教程:数据库 Migration
- 作者: 刘杰
- 来源: 技术那些事
- 阅读:94
- 发布: 2025-06-15 11:05
- 最后更新: 2025-07-02 15:06
概述
swoft 框架中,devtool
开发组件集成了数据库的初始化、迁移所需的相关功能。
可以根据数据库的 ER 图,将对应的实体,分别构建相应的 Migration 类,类可能涉及到对应数据表的创建,表结构的修改,索引的修改,甚至初始化数据的插入等等(分别对应数据库的 ddl,dml)。
-
DML(Data Manipulation Language)
数据库的基本操作语言,对应
insert/delete/update/select
。可以通过数据库事务,对操作进行提交或者回滚。 -
DDL(Data Definition Language)
数据库定义、表结构涉及相关语句:
create、alter、drop、truncate、comment、grant、revoke
。隐性提交,不能回滚。
shell
# 查看脚手架的相关命令
php bin/swoft -h
Usage:
swoft COMMAND [arg0 arg1 arg2 ...] [--opt -v -h ...]
Options:
--debug Setting the application runtime debug level(0 - 4)
--no-color Disable color/ANSI for message output
-h, --help Display help message for application or command
-V, --version Display application version information
--expand-cmd Expand sub-commands for all command groups
Available Commands:
agent This is an agent for Apllo config center
app There are some help command for application[by devtool]
dConf There are some help command for application[by devtool]
dclient Provide some simple tcp, ws client for develop or testing[by devtool]
demo Class DemoCommand
dinfo There are some commands for application dev[by devtool]
dtool There are some commands for application dev[by devtool]
entity Generate entity class by database table names[by devtool]
http Provide some commands to manage the swoft HTTP server(alias: httpsrv)
migrate Manage swoft project database migration commands[by devtool](alias: mig)
process Provides some command for manage process pool
rpc Provide some commands to manage swoft RPC server
tcp Provide some commands to manage swoft TCP server(alias: tcpsrv)
test Class TestCommand
ws Provide some commands to manage swoft websocket server(alias: wsserver,websocket)
Migration 注解(标签)
-
time
指定本次迁移的时间,据此对 migration 表进行查询,判断此次升级是否成功,还是回滚。默认为 0。
-
pool
指定当前迁移对象本次迁移要使用的数据库连接池,字符串型,可以指定多个,默认使用默认数据库连接池
db.pool
。
注解示例
php
// 只指定时间
@Migration(time=20190913232743)
// 指定时间和可用的连接池
@Migration(time=20190630164222, pool="db.pool,db1.pool")
Migration 命令
-
Migration 创建
会在 Migration 的指定路径下,根据给定的名称生成一个新的 Migration 基本类框架。
php bin/sowft mig:create test
创建一个名字为 test 的 Migration(类名会自动首字母大写)。创建时候不需要连接数据库。
-
Migration 启用
将 Migration 中记录的所有 dml、ddl 语句进行执行,进行一个数据结构的初始化。
php bin/swoft mig:up test
-
Migration 关闭
执行相关数据表的(一般是删除)语句,将已经存在的表进行删除。
php bin/swoft mig:down test
注:这些命令尽量在开发环境执行,线上环境,随意使用后果自负!!!
Bean 配置
可以通过 beanFile(默认:app/bean.php
)配置,来调整一些配置:
比如通过以下配置,可以调整 migration 的查找和生成的路径,调整完毕后变成了 @base/database
,程序会从这个路径下 Migration 文件夹中查找和生成最终 Migration 的名字。
php
return [
// 配置 migrationManager 的查找路径,此路径默认为 app/Migration
'migrationManager' => [
'migrationPath' => '@base/database',
],
];
PS:beanFile 中配置的 bean 定义如果不存在 class 关键字,表示要配置一个已有的 bean 的相关属性。
Migration 实现
Migration 脚手架
最简单的创建方式,就是通过 swoft 的 console 命令进行创建:
php
// 执行如下命令可以创建对应的 Migration 的基本框架.
$ php bin/swoft mig:create cms
Generate migrate /var/www/swoft-app/database/Migration/Cms.php, ensure continue ?
Please confirm (yes|no)[default:yes]:
yes
Migration Create Success
className Cms
file /var/www/swoft-app/database/Migration/Cms.php
// 执行创建指定 migration 的表结构
php bin/swoft mig:up cms
// 执行删除指定 migration 中的表结构
php bin/swoft mig:down cms
// 执行根据数据表创建实体类,最后参数为表名称
php bin/swoft entity:c user
// 更详细的语句,后台执行创建
php bin/swoft entity:create -d swoft --table tb_content --table_prefix tb_ --remove_prefix tb_
通过交互,可以方便的创建一个新的 Migration 框架。
代码编写
主要注意以下几个方面:
-
类名
完整的 migration 名称为
sprintf('%s%s', $className, $time)
,即类名和时间拼接到一起的名字,用户在执行 migration 命令时候,会通过stripos($migrationName, $name)
看时候匹配到了相应的迁移过程,匹配到的所有迁移过程会按照时间从低到高,依次执行。此种方式可以用来配合数据库的逐步升级过程。 -
类标签
@Migration(time=20250501120000)
这个是用来记录将要执行的 Migration 的时间,每次执行后,如果时间不变动,就不会再次执行(幂等性)
时间字符串为 14位(YmdHis)年月日时分秒
-
up 方法,执行此次迁移涉及的相关操作
-
down 方法,回滚此次迁移操作
当执行命令
php
<?php declare(strict_types=1);
namespace Database\Migration;
use Swoft\Devtool\Migration\Migration as BaseMigration;
use Swoft\Devtool\Annotation\Mapping\Migration;
use Swoft\Db\Schema\Blueprint;
/**
* Class User
* @Migration(time=20250310101700)
*/
class User extends BaseMigration
{
/**
* @inheritDoc
*/
public function up(): void
{
// 用户主表
$this->schema->createIfNotExists('user', function (Blueprint $blueprint) {
$blueprint->comment('用户主账号表');
$blueprint->string('id', 32)->comment('用户唯一ID');
$blueprint->string('name', 100)->comment('用户名');
$blueprint->string('password', 64)->comment('密码');
$blueprint->string('salt', 6)->comment('密码盐');
$blueprint->bigInteger('create_time', false, true)->comment('创建时间');
$blueprint->bigInteger('update_time', false, true)->comment('更新时间');
// 普通btree 索引,前缀索引20位字符,注意这里必须用表达式对象,保证sql按用户自定义格式拼接
$blueprint->index([Expression::new('`name`(20)')], 'idx_name');
// 唯一索引
$blueprint->unique('md5', 'uq_md5');
// 普通索引,字段名可以用字符串,或者数组。
// 前缀索引不用表达式对象,会造成整个部分作为字段名引用,进而导致字段无法找的语法问题
$blueprint->index('create_time', 'idx_create_time');
$blueprint->engine = 'Innodb';
$blueprint->charset = 'utf8mb4';
});
}
public function down(): void
{
$this->schema->dropIfExists('user');
}
}
保证生成sql 的关键字的正确分隔
必要时候要使用 Expression 对象,来封装拼接 sql 的值,这样不会被 sql 将某一部分视为一个整体进行引用。
执行结果
Migration 执行后,首先会通过指定连接池,去相应的数据库中找到 migration 数据表,没有就会新建一个。
然后会将此次执行的 Migration 记录插入到表中,up 命令和 down 命令互为相反,一个建表结构,一个删除表结构。同一命令可以反复执行(幂等性)。可以快速批量创建数据表,方便进行程序测试。
mysql
-- migration 表格式
CREATE TABLE `migration` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`time` bigint NOT NULL,
`is_rollback` tinyint NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
-- 数据
-- id name time is_rollback
-- 1 Database\Migration\User 20250310101700 1
-- 其中 name 是执行的 Migration 名字记录,time 是时间
-- is_rollback=1 表示回滚过(down执行后),
-- is_rollback=2 表示已经完成(up命令执行过后)
注意:
此组件,一般用在开发阶段,方便开发可以对数据结构进行统一管理。
数据库的 DDL 处理一般由专门 DBA 处理,不一定可以通过此工具直接执行。
另外,进行 DDL 操作的连接池,最好要跟 DML 普通数据操作的连接池分开来(使用不同权限账号),DDL 连接池不对应用上层暴露,以保证数据库安全。