【问题标题】:Simplest method for declaratively applying a SQL schema to a table?以声明方式将 SQL 模式应用于表的最简单方法?
【发布时间】:2020-07-02 18:53:20
【问题描述】:

目标:我正在寻找一种将 SQL 表架构“应用”到数据库的声明性和可重复的方式

我尝试过的

下面是一个 SQL 脚本,它可以执行我想要的操作(根据我对 MySQL 的肤浅知识和一些手动测试,尽我所能判断):

  1. 如果表不存在,则创建它
  2. 如果表确实存在,它会确保它具有所需的架构
-- create table

create table if not exists `EntryType` (
  `EntryCode` varchar(2) primary key,
  `Name` varchar(256) not null
) engine = InnoDB default charset = utf8mb4;

-- modify table

alter table `EntryType`
  engine = InnoDB,
  character set utf8mb4;

alter table `EntryType`
  modify `EntryCode` varchar(2),
  drop primary key,
  add primary key (`EntryCode`);

alter table `EntryType`
  modify `Name` varchar(256) not null;

这种方法的问题

  • 重复:重复列定义、引擎和字符集两次
  • 费力:每次添加或修改表时,都需要花费大量时间来制作这些查询并手动测试它们
  • 命令式:从根本上说,这是对应该声明性的事物的命令式方法

问题:是否有一些安全的方式以声明方式“应用”表架构?

  • 幂等:可以以完全相同的最终状态应用任意次数
  • 无论表是否已存在都有效
  • 无论表是否已包含数据都有效
  • 无论是否存在对其他表的约束和外键引用都有效

偏好:

  1. 纯 SQL 解决方案是理想的
  2. 可靠且易于使用的 CLI 解决方案会起作用
  3. 也可以接受相对简单的手工编码 SQL 或 Node.js 解决方案

【问题讨论】:

  • 你想要Skeema。它不是纯 SQL 解决方案,但没有纯 SQL 解决方案。 Skeema 符合您的描述。
  • 您正在描述通常称为“迁移”的内容,并且有许多工具可以帮助您做到这一点。如果你喜欢 Node,那么Sequelize 有一个你可以使用的迁移系统。
  • Skeema 看起来确实符合我的要求。 ???试试看。
  • @tadman,迁移使用仍然使用命令式方法,但我正在寻找一个声明性解决方案。
  • SQL 本身无法解决这个问题,因为 SQL 的功能不够完整,无法做到这一点。您将需要其他东西来与服务器交互并执行此操作。任何纯粹的“声明性”迁移系统实际上都是垃圾,因为它会在短时间内把事情弄得一团糟。你想要控制它正在做什么。

标签: mysql sql database-schema


【解决方案1】:

正如Bill Karwin 所建议的那样,Skeema.io CLI 最终在一些简单的测试中运行良好。

文档在指导您完成设置过程方面做得并不好,所以我在这里记录了我发现的内容。

首次获取架构

the github repo releases page下载一个ZIP文件并解压。

skeema 二进制文件放在项目中的某个位置。在我的项目根目录中,我把 它位于bin 文件夹中,因此从项目根目录开始,路径为./bin/skeema

然后,确保您的 MySQL 数据库正在运行并且您拥有连接信息。我的本地运行在127.0.0.1,端口3306(MySQL 默认,所以我不必输入)。

从项目根目录,我输入了以下命令,通过获取数据库模式的当前状态来初始化事物。

./bin/skeema init -h 127.0.0.1 -u root -p --schema=MyDB -d schemas

一些细节:

  • 我使用--schema=MyDB 选项仅跟踪一个数据库。如果您忽略它,它将跟踪它找到的所有数据库。
  • -d schemas 选项表示将配置和架构文件存储在schemas 目录中。
  • 使用-p选项,运行命令后会提示输入密码。

然后它会连接并检查您的数据库,创建schemas 目录,并在其中写入一些代表当前模式状态的文件。您会注意到数据库中每个表都有一个.skeema 配置文件和一个.sql 文件。

配置调整

然后我进入schemas/.skeema 配置文件并将[production] 部分重命名为[development],因为这实际上是一个开发实例。通过这样做,我必须在每个命令中指定development,因为skeema 假定production 是默认值。

[可选,仅限 Node.js 项目] skeema 命令旨在从包含 .skeema 配置文件的文件夹中运行,但我不想担心这个,所以我创建了一个我的 Node.js package.json 文件中的脚本,基本上每次都会为我执行此操作。

{
  "scripts": {
    "skeema": "cd schemas && ../bin/skeema"
  },
}

现在我可以从项目根目录(或项目中的任何其他位置)键入以下内容:

npm run skeema

第一次架构更改

schemas/.skeema 配置文件中,我做了一些更改以纠正设置这些表时的字符编码错误:

  • default-character-set=utf8 更改为default-character-set=utf8mb4
  • default-collation=utf8_general_ci 更改为default--collation=utf8mb4_unicode_ci

我还在.sql 文件之一中添加了一个新列:

CREATE TABLE `EntryType` (
  `EntryCode` varchar(2) NOT NULL,
  `Name` varchar(256) NOT NULL,
  `Foo` varchar(3), -- new column
  PRIMARY KEY (`EntryCode`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

推送架构更改

第一步是看有没有schema差异:

npm run skeema diff development

您所做的架构更改的输出,例如:

2020-07-02 19:32:14 [INFO]  Generating diff of 127.0.0.1:3306 MyDB vs
                            /Users/chriscalo/Projects/my-project/schemas/*.sql
-- instance: 127.0.0.1:3306
USE `MyDB`;
ALTER TABLE `EntryType` ADD COLUMN `Foo` varchar(3) DEFAULT NULL;
2020-07-02 19:32:15 [INFO]  127.0.0.1:3306 MyDB: diff complete

然后推送架构更改:

yarn run skeema push development

就是这样!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-07-10
    • 1970-01-01
    • 2016-10-08
    • 2014-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多