Play Framework的数据库迁移方案——Evolutions
2020-08-19 19:50:44 +08 字数:1704 标签: Scala只要有个数据库,都需要迁移(Migration)方案,除非一版定稿、再不修改。
Play Framework在1.x时代,使用的是Module migrate; 而在2.x时代,使用的是Evolutions。 本文介绍Evolutions的原理与配置。
Evolutions简介 ¶
Evolutions是Play自带的一个组件,负责实现数据库Schema的变更管理。 在使用Slick的情况下,Play还需要一个额外的[play-slick-evolutions]来对接Evolutions。 [play-slick-evolutions]是play-slick的一个附带组件。
它和Module migrate比较类似,通过维护一系列的1.sql
、2.sql
等,来保留数据库Schema演进的状态。
这些SQL需要手写,并且人工确保和ORM代码保持一致。
Evolutions会根据这些SQL,提供半自动或全自动的数据库维护操作。
在数据库中,会额外多一个play_evolutions
表,记录升降级状态。
半自动操作大概是这样的:
根据提示,在开发时手动点击【Apply this script now!】,就可以执行SQL、升级数据库。 也会出现其它类型的提示,都可以根据提示来操作。
全自动操作只需要增加一行配置,见下一节。 原理大概是通过Evolutions自带的依赖注入,利用Slick完成数据库操作。
Evolutions配置 ¶
官网提供的配置,主要是针对内存数据库。 对Slick场景的Evolutions配置,语焉不详。
实际上,在build.sbt
中主要就是加两行:
libraryDependencies ++= Seq(
"com.typesafe.play" %% "play-slick" % "4.0.0",
"com.typesafe.play" %% "play-slick-evolutions" % "4.0.0",
)
这里要注意,必须把jdbc
和evolutions
删除。
前者有依赖注入的冲突,后者完全可以去掉。
虽然Play官网的2.7文档写着,上面两个依赖应该使用3.0.0
版本。
但是根据play-slick源码的README,在Slick
是3.3.1
的情况下,应该使用4.0.0
。
Plugin version | Play version | Slick version | Scala version |
---|---|---|---|
5.0.x | 2.8.x | 3.3.2+ | 2.12.x/2.13.x |
4.0.2+ | 2.7.x | 3.3.2+ | 2.11.x/2.12.x/2.13.x |
4.0.x | 2.7.x | 3.3.x | 2.11.x/2.12.x |
3.0.x | 2.6.x | 3.2.x | 2.11.x/2.12.x |
2.1.x | 2.5.x | 3.2.0 | 2.11.x |
2.0.x | 2.5.x | 3.1.0 | 2.11.x |
1.1.x | 2.4.x | 3.1.0 | 2.10.x/2.11.x |
1.0.1 | 2.4.x | 3.0.1 | 2.10.x/2.11.x |
1.0.0 | 2.4.x | 3.0.0 | 2.10.x/2.11.x |
0.8.x | 2.3.x | 2.1.0 | 2.10.x/2.11.x |
0.7.0 | 2.3.x | 2.0.2 | 2.10.x |
0.6.1 | 2.2.x | 2.0.x | 2.10.x |
0.5.1 | 2.2.x | 1.0.x | 2.10.x |
在build.sbt
配置完毕后,conf/application.conf
中只需要添加两行即可:
play.evolutions.enabled=true
play.evolutions.autoApply=true
第一句其实默认就是true
,但求心安。
第二句是自动升级,避免手动点击调试页面的尴尬。
如果可以,第二句最好只在生产环境的某一个服务配置,避免服务更新与动态扩容时对数据库的冲击。
SQL ¶
Evolutions的SQL,需要放置在conf/evolutions/default/
下,以1.sql
、2.sql
方式命名。
default
是数据库的默认配置名。
如果Slick配置中支持了多数据库,这里也支持按数据库名称配置多个目录的升降级SQL。
conf/evolutions/
└── default
├── 1.sql
└── 2.sql
PostgreSQL的示例如下。
1.sql
内容:
-- Users schema
-- !Ups
CREATE TABLE IF NOT EXISTS "USER" (
"id" bigserial NOT NULL PRIMARY KEY,
"email" varchar(255) NOT NULL,
"password" varchar(255) NOT NULL,
"fullname" varchar(255) NOT NULL,
"isAdmin" boolean NOT NULL
);
-- !Downs
DROP TABLE IF EXISTS "USER";
2.sql
内容:
-- Add Post and update User
-- !Ups
ALTER TABLE IF EXISTS "USER"
ADD COLUMN IF NOT EXISTS "age" int;
CREATE TABLE IF NOT EXISTS "Post" (
"id" bigserial NOT NULL PRIMARY KEY,
"title" varchar(255) NOT NULL,
"content" text NOT NULL,
"postedAt" date NOT NULL,
"author_id" bigint NOT NULL,
FOREIGN KEY ("author_id") REFERENCES "USER" ("id")
);
-- !Downs
ALTER TABLE IF EXISTS "USER"
DROP COLUMN IF EXISTS "age";
DROP TABLE IF EXISTS "Post";
其中,第一行注释是写给人看的描述,执行时无实质用途。
-- !Ups
后面是升级时执行的内容,而-- !Downs
是降级时执行的内容。
和Play 1.x时代的Module migrate相比,这种去掉create.sql
、单文件完成一次升降级的设计,更加简洁。
开发时,确保每次提交数据库Schema变更操作时,都包含对应的x.sql
文件, x
按既有次数递增。
这样,每一个数据库状态,就都被记录下来,技术上可以做到从任意版本到另一版本的升降级。
注意:这个文件中不要乱加注释,否则会影响Evolutions的解析,出现额外错误。
推荐使用pgformatter格式化。
查询升级情况 ¶
通过以下select
语句,可以在数据库中查询到Evolutions的运行结果。
# select id, hash, applied_at, state, last_problem from play_evolutions;
id | hash | applied_at | state | last_problem
----+------------------------------------------+-------------------------+---------+--------------
1 | 128a219f18c09bdee2246e68dbbd74e177d32deb | 2020-08-19 19:42:57.503 | applied |
2 | 362b9bcdc8586247f2a74917e0f6d1d41f058358 | 2020-08-19 19:42:58.134 | applied |
参考 ¶
资料比较少,除了官网,基本上只有上GitHub去看README和源码了。