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 的这个开关是文件级的。

理解执行顺序和版本记录
普通迁移通常是“开始事务、执行 SQL、写版本记录、提交”。加上 NO TRANSACTION 后,Goose 会在数据库连接上逐条执行迁移语句,成功后再以非事务方式写入版本记录。这个顺序意味着“版本号已经记录”不等于每一条业务 SQL 都具备原子性。
例如文件前两条语句成功,第三条因为权限或数据库能力失败,前两条不会因 Goose 自动回滚而消失。此时先暂停后续迁移,记录已完成的对象和失败 SQL,再决定是补偿、人工清理,还是修复文件后重新执行。不要直接反复执行一个可能重复创建对象的文件。
| 场景 | 建议 |
|---|---|
| 普通 DDL 或初始化数据 | 保留默认事务,获得整体回滚 |
| 数据库禁止事务的特殊 DDL | 单独文件使用 NO TRANSACTION |
| 多条互相依赖的高风险操作 | 拆成多个可检查的小迁移 |
失败恢复要按非事务迁移设计
非事务迁移的重点不是“如何强行重跑”,而是提前设计失败后的状态判断。上线前先用目标版本、权限和数据库能力做预检;执行时让每条语句尽量幂等,或明确写出只能执行一次的前置条件;发布手册中列出已创建对象、已删除对象和对应的补偿 SQL。
如果 Up 失败,先查数据库实际状态,再决定是否修复后继续。若 Down 也包含非事务操作,回滚本身同样可能部分完成,最好把它当成一条需要观察结果的恢复流程。对于不可逆变更,优先采用备份、灰度窗口和人工确认,不要把“有 Down 文件”误认为“必然能无损回滚”。

上线前的迁移检查清单
- 确认只有确实不支持事务的语句才使用
NO TRANSACTION。 - 检查注解独占一行、没有前导空格,并位于文件顶部。
- 确认
Up唯一且Down在其后,了解两者都会跳过事务。 - 在与生产相同的数据库能力和权限下预演,记录中途失败后的实际状态。
- 为失败、补偿、重试和人工回滚分别准备可执行记录,不直接盲目重跑。
常见问题
只想让 Up 不使用事务,Down 保持事务可以吗?
不能用这个文件级注解实现。Goose 官方语义是同一文件的 Up 和 Down 都在事务外执行;如果两者需要不同策略,应拆分迁移文件或改用适合的 Go 迁移实现。
加了 NO TRANSACTION 后还需要 StatementBegin 吗?
需要时仍然需要。NO TRANSACTION 解决的是事务边界,StatementBegin/StatementEnd 解决的是 Goose 如何识别内部包含分号的复杂 SQL;它们处理的是两个不同问题。
-
187 收藏
-
412 收藏
-
114 收藏
-
241 收藏
-
101 收藏
-
317 收藏
-
113 收藏
-
419 收藏
-
112 收藏
-
394 收藏
-
479 收藏
-
204 收藏
-
357 收藏
-
102 收藏
-
422 收藏
-
331 收藏
-
241 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习