一、前言
只要开发稍微大型一点的项目,数据库都是离不开的。
rust目前并没有特别成熟的数据库框架,sea-orm这个框架是我目前所看到的成熟度最高的一个,并且仍在积极开发中。
所以本文将以sea-orm框架为基础来了解rust中数据库的基本使用。
二、项目管理
sea-orm管理数据库是通过迁移文件完成的,所以想要正常使用sea-orm框架,我们必须得对整个项目进行规划,使用方法便是工作空间。
首先下载sea-orm的命令行工具:
cargo install sea-orm-cli
这个命令行工具可以帮助我们迁移数据库、以及生成表实例等等。
然后在该工作空间内,分别执行命令:
sea-orm-cli migrate init
cargo new entity --lib
cargo new app
这三个命令用于在本工作空间内创建项目,也就是crate,其中前两个最好不要动,至于第三个命令,你可以随意修改它的名字,它是你实际写代码业务逻辑的地方。
此时我们整个工作空间看起来大致像下面这样:
注意使用sea-orm-cli生成的crate,它的名字需要我们手动添加到工作空间成员中去,至于其它两个,会自动添加。
至此我们就完成了整个项目的搭建,各个crate的作用如下:
- migration:用于管理迁移文件的crate,说白了就是这个crate可以让我们通过代码创建数据库的表,只要迁移文件在,即使你数据库被删了,也能快速恢复过来(仅限表结构,不含数据)。
- entity:用于包含所有表所对应的实体结构,你可以将其看作是数据库到代码的一个映射关系,以后你任何想要对数据库的表的增删改查操作,都要通过这个crate进行,并且这个crate中的代码后续是通过sea-orm-cli工具自动根据数据库生成的,你无需自行维护。
- app:你实际的项目业务逻辑代码,当你想要操作数据库中的表时,引入entity这个crate即可。
三、迁移文件
为了方便起见,这里使用sqlite3数据库作为演示,它无需我们去安装其它任何东西。
但无论如何,迁移文件本身是数据库无关的,所以我们先来看迁移crate为我们自动生成的代码:
首先移除掉todo!()
宏,去除警告,上面的这个迁移文件是自动为我们生成的。
首先看到这个文件的名字:m20220101_000001_create_table
,其中首字母m
是migration的缩写,后面跟着的数字是年月日、时分秒,最后的create_table
则是这个迁移文件的含义,也就是创建表的意思。
注意,这里的迁移文件后面我们是通过命令自动生成的,所以文件名格式、包括这个文件中的代码样式,都不用我们操心。
我们在自动生成的迁移文件代码中,只需要关注三个地方:
- up函数,也就是向上的意思,意味项目向前进展过程中所需要对数据库做出的修改。
- down函数,也就是向下,意味回退的意思
- Post枚举,代表这个迁移文件中所要操作的数据库表
虽然上面自动生成的代码看起来比较繁琐复杂,但实际并不难,首先我们来看标号3的表结构:
#[derive(DeriveIden)]
enum Post {
Table,
Id,
Title,
Text,
}
这里的Post
代表着表的名字,而其内的Table
字段则被用来在后续的代码中使用、指代这个本表。
因此实际上,这里的含义就是Post表中有三个字段,分别命名为Id、Title、Text。
其上的#[derive(DeriveIden)]
就不用我们管了,它是sea库本身写的过程宏,可以根据这个枚举生成一些代码,方便我们使用,是必须要写上的。
然后我们再来看up函数:
manager.create_table().await
虽然上面有一大串,但实际上就是一个函数,通过传入的manager实例调用其上的create_table函数,用于创建一个表。
这个要创建的表就是我们将要传入的参数,这个参数是通过固定Table模块内函数创建的。
比如这里是创建表,所以就要使用Table中的create函数:
Table::create()
.table(Post::Table)
.if_not_exists()
这里就是一系列的链式调用,你不需要管其它的,看这个函数名字你就知道它是在干嘛了。
table函数用来指定你想要创建的表结构,这里指定的就是本文件中的Post表,传入Post::Table
即可。
if_not_exists见名知意,就是只要不存在这张表的时候才执行创建。
再之后,就是设置这张表中的每个字段的属性:
.col(
ColumnDef::new(Post::Id)
.integer()
.not_null()
.auto_increment()
.primary_key(),
)
.col(ColumnDef::new(Post::Title).string().not_null())
.col(ColumnDef::new(Post::Text).string().not_null())
每个字段都是一列,所以调用col函数,然后根据表字段进行构建ColumnDef::new(Post::Id)
,每个字段都有四个属性:
- 类型:比如这里调用integer函数代表Id字段是数字,后面的string函数代表Title、Text字段是字符串
- 是否可以为空,也就是null,默认允许,你可以调用not_null函数设置不允许
- 是否自动自增,一般id字段需要自增,所以这里调用auto_increment函数
- 是否为主键,id字段一般为主键,所以这里调用primary_key函数将其设置为主键。
完成了一张表的代码定义之后,最后调用to_owned函数,获取这个实例的所有权,传入create_table函数,即完成了创建表的代码定义。
而与up相反的down函数,就需要写出创建表的反向操作,也就是删除表:
manager
.drop_table(Table::drop().table(Post::Table).to_owned())
.await
删除表的操作就是drop_table,其参数同样是在Table模块中,这次是删除,所以调用drop函数,通过table指定要删除的表即可。
以上便是一个完整的迁移文件构成,你可以根据以上的规律,自行定义自己的表结构以及实际操作。
同时该迁移文件需要放在lib.rs文件中进行使用,但这是其自动化的过程,并不需要我们去管理,只需要知道有这件事即可:
此时,我们只需要运行一下迁移,即可将上面的代码中定义的表生成在一张数据库中:
但前提是要添加依赖:
因为我们这里要操作的是sqlite数据库,所以就要添加sqlx-sqlite
这个特性,至于上面的runtime-tokio-rustls
,是设置运行时的意思,一般都用tokio+rustls,直接复制即可。
然后我们就可以在工作空间
的根目录
下,运行命令为:
$env:DATABASE_URL='sqlite://db.sqlite?mode=rwc'
cargo run -p migration
其中第一个命令是windows系统powershell设置环境变量,我们首先需要设置DATABASE_URL
这个环境变量的值等于我们的数据库链接。
注意:如果你使用的是其它终端,可能设置环境变量的方式和这里并不相同,所以推荐你直接使用vscode内置终端。
链接格式我们后面再详聊,这里的意思就是链接到当前目录下的db.sqlite数据库。
此时执行命令后我们就可以看到执行结果: