上文我们介绍了SQLx及SQLite,并介绍了如何使用代码同步迁移数据库。本文介绍Sqlx cli 命令行工具,介绍如何安装、使用,利用其提供的命令实现数据表同步迁移。Java生态中有flyway, sqlx cli 功能类似,利用命令行工具可以和其他语言项目工程一起使用。
数据库迁移是开发和重构应用程序数据库的过程,是应用程序开发过程的一部分。SQLx CLI是Rust crate SQLx的关联命令行实用程序,用于管理此迁移过程。在这篇文章中,我们将看看如何在Ubuntu 22.10上对MySQL使用这个命令行工具。
在尝试了SQLx CLI之后,我想说,我们实际上可以将这个CLI作为一种通用工具来管理用Rust以外的语言编写的应用程序的数据库开发。我真的很喜欢这个CLI。
SQLx CLI 安装
安装openssl
SQLx CLI文档没有提到它,但它似乎确实需要OpenSSL。我只是在尝试安装失败后才发现这个。在Ubuntu 22.10上,第一次安装尝试没有通过,它需要OpenSSL。详细日志请参见Ubuntu 22.10 SQLx CLI Failure Installation logs。
要安装OpenSSL,运行:
$ sudo apt install pkg-config
sqlx cli 安装
我们使用cargo安装SQLx CLI。在哪个目录下运行安装命令并不重要, 在Ubuntu 22.10上, 默认目录为:/home/ username /.cargo/bin/。最好把该目录添加至环境变量中,方便后续在项目中使用。
$ cargo install sqlx-cli
同步迁移数据库
数据库连接
SQLx CLI 使用.env
文件和命令行选项--database-url
。我们稍后将使用.env
文件,我们可以根据应用程序的需要向该文件添加更多运行时信息,.env
文件应该与Cargo.toml文件放在同一个目录中。
我们实际上并不需要一个现有的Rust项目来启动数据库迁移过程。但这里新建项目为了演示迁移过程。
在特定目录下,创建一个新项目sqlx-mysql-migration,并更改到项目目录:
$ cargo new sqlx-mysql-migration
$ cd sqlx-mysql-migration/
创建 .env 文件
在项目根目录下,新建.env 文件,增加数据库连接信息:
DATABASE_URL=mysql://root:passw0rd@localhost:3306/membership
我们以前在其他Rust代码中见过DATABASE_URL的值,在本例中,我们使用membership数据库。
创建数据库
现在我们已经准备好了DATABASE_URL,当然目标MySQL服务器也在运行,我们用以下命令创建数据库:
$ sqlx database create
如果没有问题,就不会有输出。我们应该使用MySQL Workbench来验证数据库是否已经创建。
我们可以删除数据库:
$ sqlx database drop
它会要求确认。同样,我们可以使用MySQL Workbench来验证数据库是否已被删除。请注意,从这一点开始,我们需要数据库存在。
初始化脚本
创建第一个数据库脚本。该命令的格式为:
## $ sqlx migrate add -r <name>
## 首个脚本我们使用init 作为name
$ sqlx migrate add -r initCreating migrations/20241126021418_init.up.sql
Creating migrations/20241126021418_init.down.sqlCongratulations on creating your first migration!Did you know you can embed your migrations in your application binary?
On startup, after creating your database connection or pool, add:sqlx::migrate!().run(<&your_pool OR &mut your_connection>).await?;
...
已经创建了名为migrations/的子目录,其中有两(2)个空文件20231008021418_init.up。SQL和20231008021418_init.down.sql。
在对应用程序数据库进行了一些更改之后,由于某些原因,我们可能希望恢复这些更改。20231008021418 _init.up.sql脚本文件是我们编写sql语句来更新数据库的地方; 脚本文件20231008021418_init.down.sql是我们编写sql语句来撤销20241126021418_init.up.sql。
migrations/20241126021418_init.up.sql 文件的内容:
ALTER DATABASE `membership` DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;DROP TABLE IF EXISTS `member`;
CREATE TABLE `member` (`id` int NOT NULL,`email` VARCHAR(255) NOT NULL,`password` varchar(100) NOT NULL,`birth_date` date NOT NULL,`first_name` varchar(32) NOT NULL,`last_name` varchar(32) NOT NULL,`gender` enum('M','F') NOT NULL,`joined_date` date NOT NULL,`created_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,PRIMARY KEY (`id`),UNIQUE KEY `email_unique` (`email`)
);
基本上,我们修改membership数据库的一些属性,然后创建第一个表:member。
20231008021418_init.down.sql 文件内容:
DROP TABLE IF EXISTS `member`;
我们撤销up脚本所做的工作:从数据库中删除成员表
运行初始化迁移
让我们运行init迁移。命令为:
$ sqlx migrate run
MySQL Workbench显示已经创建了成员表,并且还有一个额外的表_sqlx_migrations,其中有一行,这一行应该是不言自明的。让我们撤销它。命令为:
$ sqlx migrate revert
验证成员表是否已被删除,并且表_sqlx_migrations为空?
更新数据脚本1
让我们创建另一个数据库更新脚本,我们将其命名为stage1:
$ sqlx migrate add -r stage1
自动创建新的文件, 结尾_stage1.up.sql
, 修改内容:
DROP TABLE IF EXISTS `duration`;
CREATE TABLE `duration` (`id` smallint NOT NULL,`months` smallint NOT NULL,`expiry_date` date NULL,PRIMARY KEY (`id`)
) comment='Membership duration in months.';insert into duration ( id, months )
values( 1, 6 ),( 2, 12 ),( 3, 18 ),( 4, 24 );
同时修改_stage.down.sql
文件内容:
DROP TABLE IF EXISTS `duration`;
运行 stage1 命令:
$ sqlx migrate run
表_sqlx_migrations现在应该包含两个条目。还应该创建表持续时间。
回退操作
$ sqlx migrate revert
stage1 被回退,duration表被删除。
再次执行回退:
$ sqlx migrate revert
我们可以看到,最后一个更新首先被撤消。另外,成员数据库现在是一个空数据库。并且表_sqlx_migrations没有条目。