9

Play Framework的数据库迁移方案——Evolutions

 3 years ago
source link: https://note.qidong.name/2020/08/play-evolutions/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Play Framework的数据库迁移方案——Evolutions

2020-08-19 19:50:44 +08  字数:1704  标签: Scala

只要有个数据库,都需要迁移(Migration)方案,除非一版定稿、再不修改。

Play Framework在1.x时代,使用的是Module migrate; 而在2.x时代,使用的是Evolutions。 本文介绍Evolutions的原理与配置。

Evolutions简介

EvolutionsPlay自带的一个组件,负责实现数据库Schema的变更管理。 在使用Slick的情况下,Play还需要一个额外的[play-slick-evolutions]来对接Evolutions。 [play-slick-evolutions]是play-slick的一个附带组件。

它和Module migrate比较类似,通过维护一系列的1.sql2.sql等,来保留数据库Schema演进的状态。 这些SQL需要手写,并且人工确保和ORM代码保持一致。 Evolutions会根据这些SQL,提供半自动或全自动的数据库维护操作。 在数据库中,会额外多一个play_evolutions表,记录升降级状态。

半自动操作大概是这样的:

needs evolution

根据提示,在开发时手动点击【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",
)

这里要注意,必须把jdbcevolutions删除。 前者有依赖注入的冲突,后者完全可以去掉。

虽然Play官网的2.7文档写着,上面两个依赖应该使用3.0.0版本。 但是根据play-slick源码的README,在Slick3.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.sql2.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和源码了。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK