登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  Golang >  Go教程

Go Goose 怎样把指定迁移声明为不使用事务

来源:17golang原创

时间:2026-10-29 11:23:57 433浏览 收藏

Goose 默认会把一个 SQL 迁移文件放进事务。如果迁移里有数据库不允许在事务中执行的操作,例如某些建库语句或并发创建索引,就在文件顶部加入 -- +goose NO TRANSACTION。这个标记只影响当前迁移文件,Up 和 Down 都会在事务外执行。

官方地址:https://pressly.github.io/goose/

做法很简单:把 -- +goose NO TRANSACTION 放在迁移文件顶部,再保留正常的 -- +goose Up 和 -- +goose Down 区块。代价是失败时没有事务回滚,所以要把文件拆小,并准备恢复步骤。

先记住三点:注解必须独占一行且不能有前导空格;它对同一文件的 Up、Down 都生效;非事务迁移出现中途错误时,已经执行成功的语句不会被 Goose 自动撤销。

先判断哪些迁移值得关闭事务

不要因为“迁移能跑”就全都关闭事务。事务的价值是把一次迁移的多条变更当成一个整体提交,任意语句失败时由数据库回滚。只有目标数据库明确拒绝事务包裹,或者该 DDL 的语义要求在事务外执行时,才适合使用这个注解。

常见判断顺序是:先确认数据库和驱动的限制,再看语句是否必须独立提交,最后把这类变更从普通表结构迁移中拆出来。普通的建表、加列、插入初始化数据,优先保留 Goose 默认事务;并发建索引、建库等特殊操作才进入非事务迁移。

在迁移文件顶部声明 NO TRANSACTION

一个可读的 SQL 文件可以这样写。注解使用 Goose 的注释格式,必须单独占一行;Up 是前向迁移,Down 是回滚迁移。

-- +goose NO TRANSACTION
-- 这里声明当前文件的 Up 和 Down 都在事务外执行

-- +goose Up
-- 这里放必须在事务外运行的 SQL
CREATE INDEX CONCURRENTLY users_email_idx ON users (email);

-- +goose Down
-- 回滚同样不使用事务,执行前要确认数据库支持对应语句
DROP INDEX CONCURRENTLY users_email_idx;

注解放错位置、前面有缩进,或者把它写进普通 SQL 文本,都可能导致 Goose 无法按预期识别。文件里仍然只保留一个 Up 标记,Down 放在它之后;不要把一个文件中的部分语句设成事务外,Goose 的这个开关是文件级的。

Goose 迁移文件顶部的 NO TRANSACTION、Up、Down 与事务关闭关系说明图
图1:Goose 迁移文件的 NO TRANSACTION 注解位置说明图,不是截图或运行证据。

理解执行顺序和版本记录

普通迁移通常是“开始事务、执行 SQL、写版本记录、提交”。加上 NO TRANSACTION 后,Goose 会在数据库连接上逐条执行迁移语句,成功后再以非事务方式写入版本记录。这个顺序意味着“版本号已经记录”不等于每一条业务 SQL 都具备原子性。

例如文件前两条语句成功,第三条因为权限或数据库能力失败,前两条不会因 Goose 自动回滚而消失。此时先暂停后续迁移,记录已完成的对象和失败 SQL,再决定是补偿、人工清理,还是修复文件后重新执行。不要直接反复执行一个可能重复创建对象的文件。

场景建议
普通 DDL 或初始化数据保留默认事务,获得整体回滚
数据库禁止事务的特殊 DDL单独文件使用 NO TRANSACTION
多条互相依赖的高风险操作拆成多个可检查的小迁移

失败恢复要按非事务迁移设计

非事务迁移的重点不是“如何强行重跑”,而是提前设计失败后的状态判断。上线前先用目标版本、权限和数据库能力做预检;执行时让每条语句尽量幂等,或明确写出只能执行一次的前置条件;发布手册中列出已创建对象、已删除对象和对应的补偿 SQL。

如果 Up 失败,先查数据库实际状态,再决定是否修复后继续。若 Down 也包含非事务操作,回滚本身同样可能部分完成,最好把它当成一条需要观察结果的恢复流程。对于不可逆变更,优先采用备份、灰度窗口和人工确认,不要把“有 Down 文件”误认为“必然能无损回滚”。

Goose 非事务迁移逐条执行、版本记录与失败恢复策略关系说明图
图2:非事务迁移的执行与恢复边界说明图,展示风险分层而非真实运行结果。

上线前的迁移检查清单

  1. 确认只有确实不支持事务的语句才使用 NO TRANSACTION。
  2. 检查注解独占一行、没有前导空格,并位于文件顶部。
  3. 确认 Up 唯一且 Down 在其后,了解两者都会跳过事务。
  4. 在与生产相同的数据库能力和权限下预演,记录中途失败后的实际状态。
  5. 为失败、补偿、重试和人工回滚分别准备可执行记录,不直接盲目重跑。

常见问题

只想让 Up 不使用事务,Down 保持事务可以吗?

不能用这个文件级注解实现。Goose 官方语义是同一文件的 Up 和 Down 都在事务外执行;如果两者需要不同策略,应拆分迁移文件或改用适合的 Go 迁移实现。

加了 NO TRANSACTION 后还需要 StatementBegin 吗?

需要时仍然需要。NO TRANSACTION 解决的是事务边界,StatementBegin/StatementEnd 解决的是 Goose 如何识别内部包含分号的复杂 SQL;它们处理的是两个不同问题。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>