0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

用docker启动 postgres 数据库

马哥Linux运维 来源:马哥Linux运维 作者:马哥Linux运维 2022-09-06 09:34 次阅读

1 项目地址

https://github.com/golang-migrate/migrate

2 使用情景

一些项目功能会涉及到数据库和代码逻辑的修改,对于数据库的修改,虽然 gorm 之类的工具能够在代码里面适配大部分情况,但是不能覆盖所有数据库变更情况,而且也不够清晰。为清楚表示某次代码提交设计的数据库的修改并且方便 devops 部署服务,可以使用 golang-migrate 这样的工具明确的标识对于数据的某次修改,可以对这些修改做部署和回滚。

使用 golang-migrate 有两种方式,一种是使用 migrate 提供的 CLI,一种是使用 golang library。本次测试使用 migrate CLI。

2.1 支持数据库类型

Source drivers: github-ee, godoc-vfs, s3, bitbucket, go-bindata, gcs, file, github, gitlab

Database drivers: cockroachdb, firebird, postgresql, redshift, clickhouse, postgres, cockroach, firebirdsql, mysql, crdb-postgres, mongodb, mongodb+srv, neo4j, pgx, spanner, sqlserver, stub, cassandra

3 使用方法

一开始使用 mysql 做测试,结果一直提示错误,就先用 github 上的教程用 postgres 测试了一遍。之后再解决 mysql 测试的问题。

3.1 安装 migrate CLI

3.1.1 参考

https://github.com/golang-migrate/migrate/tree/master/cmd/migrate

3.1.2 安装

直接 Release Downloads 下载对应版本即可。官网上的说明会让人误以为用 migrate CLI 的版本只支持某种数据库,但是实际测试发现下载的 migrate CLI 可以支持各种 Database drivers。

3.2 postgres 测试

3.2.1 参考

https://github.com/golang-migrate/migrate/blob/master/database/postgres/TUTORIAL.md

3.2.2 启动 postgres 数据库

在 192.168.10.212 这台测试服务器上用 docker 启动 postgres 数据库


dockerrun--namepostgres-ePOSTGRES_PASSWORD=mysecretpassword-dpostgres:14.0

进入 postgres 容器运行 psql -h localhost -U postgres -w -c "create database example;"来创建 example 数据库。

3.2.3 创建某次数据库变更的 sql 文件

mkdir migrations #首次执行,用于存放变更的 sql 文件

比如说这次修改我们需要新增一个 users 的表,

migrate create -ext sql -dir ./migrations -seq create_users_table

这个命令会在 migrations 目录下生成两个文件000001_create_users_table.up.sql 和000001_create_users_table.down.sql , 000001 是某次修改的版本号,000001_create_users_table.up.sql 用来存放创建 users 表的 sql 脚本,000001_create_users_table.down.sql 用来存放回滚这次操作的 sql 脚本。migrate create 命令只负责创建文件,sql 文件的内容需要我们手动编辑。

migrations├── 000001_create_users_table.down.sql├── 000001_create_users_table.up.sql

编辑000001_create_users_table.up.sql

CREATE TABLE IF NOT EXISTS users(   user_id serial PRIMARY KEY,   username VARCHAR (50) UNIQUE NOT NULL,   password VARCHAR (50) NOT NULL,   email VARCHAR (300) UNIQUE NOT NULL);

编辑000001_create_users_table.down.sql

DROP TABLE IF EXISTS users;

3.2.4 应用某次数据库修改

migrate 的 up 子命令用来应用某一次数据库变更, down 子命令用来回滚数据库变更操作。


比如 up [N], N 表示执行多少个数据库变更任务,那具体是执行 ./migrations 下面的哪些 sql 脚本呢?

  up [N]       Apply all or N up migrations  down [N] [-all]    Apply all or N down migrations Use -all to apply all down migrations

首次执行 migrate up 命令后,会在数据库中添加 schema_migrations 表,这个表有两个字段:version 和 dirty,version 用来表示当前数据库对应 ./migrations 下面的那个版本,比如第一次执行 migrate up 1 后,如果执行成功了, schema_migrations 表中的 version=1,说明当前数据库对应的是000001_create_users_table.up.sql 这个版本 dirty=f(false),执行到 version=1 这次的变更没有出错。如果 dirty=t(true) 会涉及要怎么修复这个错误的问题。

3.2.4.1 首次执行 migrate up

migrate -database 'postgres://postgres:mysecretpassword@192.168.10.212:5432/example?sslmode=disable' -path ./migrations up 11/u create_users_table (47.755135ms)

执行 migrate up 后,数据库中增加了 users 表和 schema_migrations 表

example=# d                List of relations Schema |       Name        |   Type   |  Owner--------+-------------------+----------+---------- public | schema_migrations | table    | postgres public | users             | table    | postgres public | users_user_id_seq | sequence | postgres(3 rows)
example=# d users;                                       Table "public.users"  Column  |          Type          | Collation | Nullable |                Default----------+------------------------+-----------+----------+---------------------------------------- user_id  | integer                |           | not null | nextval('users_user_id_seq'::regclass) username | character varying(50)  |           | not null | password | character varying(50)  |           | not null | email    | character varying(300) |           | not null |Indexes:    "users_pkey" PRIMARY KEY, btree (user_id)    "users_email_key" UNIQUE CONSTRAINT, btree (email)    "users_username_key" UNIQUE CONSTRAINT, btree (username)

example=# select * from schema_migrations; version | dirty---------+-------       1 | f(1 row)

3.2.4.2 回滚操作

migrate -database 'postgres://postgres:mysecretpassword@192.168.10.212:5432/example?sslmode=disable' -path ./migrations downAre you sure you want to apply all down migrations? [y/N]yApplying all down migrations1/d create_users_table (31.550358ms)

migrations down 后,数据库恢复到应用 create_users 之前的状态,users 表被删除,schema_migrations 表记录被删除

example=# select * from schema_migrations ; version | dirty---------+-------(0 rows)

3.2.5 应用多次修改

为了测试 migrations up [N] 执行多次修改的情形,第二次修改我们使用事务为 users 表增加 COLUMN,

migrate create -ext sql -dir ./migrations -seq add_mood_to_users , migrations 目录下会增加000002_add_mood_to_users.up.sql 和000002_add_mood_to_users.down.sql 两个文件。

000002_add_mood_to_users.up.sql :

BEGIN;CREATE TYPE enum_mood AS ENUM ( 'happy', 'sad', 'neutral');ALTER TABLE users ADD COLUMN IF NOT EXISTS mood enum_mood;COMMIT;

000002_add_mood_to_users.down.sql :

BEGIN;
ALTER TABLE users DROP COLUMN IF EXISTS mood;DROP TYPE enum_mood;
COMMIT;

第三次修改为 users 表增加 role_id 这个 COLUMN

migrate create -ext sql -dir ./migrations -seq add_roleid_to_users , migrations 目录下会增加000003_add_roleid_to_users.up.sql 和000003_add_roleid_to_users.down.sql 两个文件。

000003_add_roleid_to_users.up.sql

ALTER TABLE users ADD COLUMN IF NOT EXISTS role_id INTEGER;

000003_add_roleid_to_users.down.sql

ALTER TABLE users DROP COLUMN IF EXISTS role_id;

这样 migrations 目录下有如下6个 sql 文件:

.└── migrations    ├── 000001_create_users_table.down.sql    ├── 000001_create_users_table.up.sql    ├── 000002_add_mood_to_users.down.sql    ├── 000002_add_mood_to_users.up.sql    ├── 000003_add_roleid_to_users.down.sql    └── 000003_add_roleid_to_users.up.sql

3.2.5.1 应用多次修改

执行 migrate down 回滚 migrations 目录中所有修改。migrate -database 'postgres://postgres:mysecretpassword@192.168.10.212:5432/example?sslmode=disable' -path ./migrations down

migrate up 表示执行 migrations 目录中所有 up.sql 脚本。migrate -database 'postgres://postgres:mysecretpassword@192.168.10.212:5432/example?sslmode=disable' -path ./migrations up

migrate up [N], 表示从 schema_migrations 表的 version 的值后再执行 N 个部署。假设 schema_migration 中 version=1,migrate up [2] 就会执行 migrations 目录中 000001* 之后的000002_add_mood_to_users.up.sql 和000003_add_roleid_to_users.up.sql 两个操作。

3.2.6 测试执行失败的情况

首先执行 migrate down 回滚所有操作,然后执行 migrate up 2 应用000001_create_users_table.up.sql 和000002_add_mood_to_users.up.sql 。接下来我们修改000003_add_roleid_to_users.up.sql ,使得000003_add_roleid_to_users.up.sql 语法错误

➜  postgres migrate -database 'postgres://postgres:mysecretpassword@192.168.10.212:5432/example?sslmode=disable' -path ./migrations down  # 回滚所有操作Are you sure you want to apply all down migrations? [y/N]yApplying all down migrationsno change➜  postgres➜  postgres➜  postgres migrate -database 'postgres://postgres:mysecretpassword@192.168.10.212:5432/example?sslmode=disable' -path ./migrations up 2       # 应用 `000001_create_users_table.up.sql` 和 `000002_add_mood_to_users.up.sql`1/u create_users_table (47.883494ms)2/u add_mood_to_users (82.025579ms)➜  postgres➜  postgres cat migrations/000003_add_roleid_to_users.up.sqlALTER TABLE users ADD COLUMN role_id INTEGER errtest;%# 修改 000003_add_roleid_to_users.up.sql 增加 errtest 到语句末尾,使得 sql 语法错误
➜  postgres migrate -database 'postgres://postgres:mysecretpassword@192.168.10.212:5432/example?sslmode=disable' -path ./migrations up 1  # 执行错误error:migrationfailed:syntaxerroratornear"errtest"(column46)inline1:ALTERTABLEusersADDCOLUMNrole_idINTEGERerrtest;(details:pq:syntaxerroratornear"errtest")

这个时候查询 postgres 数据库的 schema_migrations 表,version=3,说明当前执行到 000003, 但是 dirty=t 说明执行有错误。

example=# select * from schema_migrations ; version | dirty---------+-------       3 | t(1 row)

然后修正000003_add_roleid_to_users.up.sql 的语法错误(去掉多余的 “errtest”),再次执行 migrate up 1,这个时候还是提示错误,因为 version=3 的 dirty=t,这个时候需要使用 migrate force 3 来确认说 version=3 的错误问题已修复,而且需要执行 migrate down 1 将 version 回退到 version=2 ,才能继续执行。

postgres migrate -database 'postgres://postgres:mysecretpassword@192.168.10.212:5432/example?sslmode=disable' -path ./migrations up 1error: migration failed: syntax error at or near "errtest" (column 60) in line 1: ALTER TABLE users ADD COLUMN IF NOT EXISTS role_id INTEGER errtest; (details: pq: syntax error at or near "errtest")➜  postgres migrate -database 'postgres://postgres:mysecretpassword@192.168.10.212:5432/example?sslmode=disable' -path ./migrations force 3➜  postgres migrate -database 'postgres://postgres:mysecretpassword@192.168.10.212:5432/example?sslmode=disable' -path ./migrations down 13/d add_roleid_to_users (34.332954ms)➜  postgres migrate -database 'postgres://postgres:mysecretpassword@192.168.10.212:5432/example?sslmode=disable' -path ./migrations up 13/u add_roleid_to_users (36.832839ms)

3.3 mysql 测试

说回前面说的测试 mysql 出现错误的问题,错误提示如下:

migrate -database mysql://root:x*xxx@192.168.10.212:3306/temp -path ./migrations upzsh: no matches found: mysql://root:x*xxx@192.168.10.212:3306/temp

查了一下这个错误是因为我使用的 shell 是 zsh, zsh 会自动解释 * ?等字符,而不是把 * ?留给命令 migrate 来解析,导致了错误,解决方案是在 ~/.zshrc 中加入:setopt no_nomatch 。另外一个解决方法是把 -database 参数的值加上引号 migrate -database 'mysql://root:x*xxx@192.168.10.212:3306/temp' -path ./migrations up

修正了 zsh 的问题后,再次执行 migrate up,还是提示错误:

migrate -database mysql://root:x*xxx@192.168.10.212:3306/temp -path ./migrations uperror: default addr for network '192.168.10.212:3306' unknown

这次的错误是因为 mysql 的 url 书写格式问题,mysql 的 url 需要写成 mysql://root:passwd@tcp(192.168.10.212:3306)/database 这样的格式。

审核编辑:彭静
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 服务器
    +关注

    关注

    12

    文章

    8113

    浏览量

    82499
  • 数据库
    +关注

    关注

    7

    文章

    3590

    浏览量

    63365
  • Docker
    +关注

    关注

    0

    文章

    437

    浏览量

    11602

原文标题:Go 语言数据库迁移工具 golang-migrate

文章出处:【微信号:magedu-Linux,微信公众号:马哥Linux运维】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    Delphi做中BDE连接SQL数据库(学习Delphi环境中数据库操作的方法和数据库应用程序

    Delphi做数据库开发的介绍通过使用Delphi中BDE连接SQL数据库,掌握Delphi环境中数据库操作的最基本的方法和Delphi下数据库
    发表于 05-10 11:09

    labview 数据库操作问题

    各位大侠,现在要用labview 连接数据库,进行相关的数据库操作,刚开始 LABSQL但是用了几天发现,使用网络数据库而且同时又几台客户端同时使用时会偶尔报错,看了相关的资料,好像
    发表于 07-23 17:06

    labview数据库清空压缩问题

    各位大神,我labview的database对ACCESS数据库进行操作,我数据数据库中存的太多想按日期删除,删除之后不是还得压缩数据库
    发表于 11-15 09:29

    数据库连接

    在利用 LabVIEW数据库工具包操作数据库之前,需要先连接数据库,这就像操作文件之前,先要打开文件一样。在这里我们利用UDL连接数据库。Microsoft设计的ODBC标准只能访问关
    发表于 06-29 21:29

    【Nanopi2试用体验】高级(九):Nanopi2上配置PostgreSQL数据库

    PostgreSQL 命令窗口默认的数据库名称和数据库用户名称都是 “postgres”。切换到 postgres 用户进行 postgresql# sudo -u
    发表于 01-27 20:48

    请教labSQL读写数据库时慢

    本帖最后由 路的追逐 于 2016-6-24 17:15 编辑 如图,请教labSQL读写数据库时,每次启动读写都会占用全部CPU,0.3左右秒时间导致其他程序暂停了0.3秒, 请教大家有没有办法让labsql读写时不独
    发表于 06-24 11:50

    数据库管理

    如题:labview操作access数据库做公司测试流程管控。因测试数据量大,数据生成多,现在accdb文件已经有50M了,现在发现数据库
    发表于 11-08 16:58

    数据库读写缓慢

    的labview DCT读取访问数据库,现在的数据库就40兆大小,写入数据库挺快的,读取数据库一次至少需要2秒的时间,请问怎么回事?
    发表于 11-04 08:02

    mysql数据库跑在docker

    docker中使用MySQL数据库
    发表于 08-15 14:26

    Java与'嵌入式' PostgreSQL数据库单元测试的相关资料分享

    。但总难免会用到特定数据库的特性,这时候就无法前述各种数据库进行测试了。非要单元测试中覆盖到所用的数据库特性的话可以选择
    发表于 12-21 07:56

    请问HarmonyOS数据库的话需要安装吗?

    各位老师好,刚刚接触鸿蒙开发,官方文档未找到安装数据库的过程,就有怎么数据库了。我现在用的是模拟器调试,采用的是uri 方式,请问我自己想在真机上调试访问本地数据库怎么做?
    发表于 06-09 10:31

    什么是Postgres?Postgres是什么意思

    Postgres 传统的关系型数据库管理系统 ( DBMS ) 支持一个由命名关系(表)组成的集合(包括特定类型的属性/字段)组成的数据模型.在现代的商用系统中,可能的类型通常
    发表于 12-26 14:04 6711次阅读

    MySQL与Postgres两大免费数据库大不同

    7月末,优步公司宣布将数据库Postgres切换到MySQL,个中原因又是什么呢?
    发表于 08-01 10:40 3151次阅读

    Uber为什么从Postgres迁移到MySQL

    。特别是在之前一些使用Postgres的案例中,现在则改用Schemaless(一个基于MySQL的全新数据库分片)。本文将探索Postgres的缺陷,解释迁移到MySQL的基础上构建
    发表于 09-30 14:45 4次下载
    Uber为什么从<b class='flag-5'>Postgres</b>迁移到MySQL

    数据库到底要不要上Docker

    近2年Docker非常的火热,各位开发者恨不得把所有的应用、软件都部署在Docker容器中,但是您确定也要把数据库也部署的容器中吗?
    的头像 发表于 04-06 09:59 2238次阅读