# v0.25 事务错误验收(2026-09-26) 目标是让业务可靠地区分错误阶段和框架实际掌握的事务结果。保持 InTx 签名,保留原始/回滚错误链;不引入业务补偿、文件删除或事务重试。 ## 回归 - `GO_OMNI_SCAFFOLD_INTEGRATION=1 go test -race ./...`:49 个有测试的包通过,包含既有生成消费者、响应目录、生命周期、上传下载、配置等回归。 - `GOTOOLCHAIN=go1.22.12 go test ./database ./errors ./app`:通过。 - `go vet ./...`、`go build ./...`:通过。 - `go test -race ./database -run '^TestInTxCancellation' -count=20`:通过,包含 20 × 128 次取消与回滚竞争检查。 - `go run ./examples/transactions`:六种结果通过,包括“已保存但提交报错”时不清理文件的演示决策;示例没有真实文件删除。 - checked-in managedService 的生成检查、race 和根目录 build 通过。 | 场景 | 验证结果 | | --- | --- | | 开启失败 | callback 不执行,StageBegin/NotStarted,原始驱动或 context 原因可 Is/As;nil DB、nil callback 在开启前报错 | | 成功事务 | callback/Commit 各一次,返回 nil,不再调用显式 Rollback;context、隔离级别、只读选项传递保持 | | 回调失败 | 显式回滚 nil 才返回 Work/RolledBack;原始业务原因可 Is/As;回滚报错为 Unknown 且两条原因完整保留 | | 提交失败 | 同样的驱动错误分别模拟已保存/未保存,都返回 Commit/Unknown;超时、ErrBadConn 也不当成回滚;不重试 Commit/callback | | 取消 | 开启前取消、回调取消、自动回滚完成、取消与显式回滚竞争、提交过程中取消;ErrTxDone 从不表示回滚成功 | | 原因链 | 外层再次 `%w` 包装后 As/Is 可用;主要 typed cause 优先,回滚 typed cause 可单独找到;嵌套 TxError 不压平 | | 异常与隔离 | panic 原值传播,Goexit 正常展开;都尝试一次回滚,不提交;64 个并发调用的原因/结果互不串扰 | | HTTP 兼容 | 回调返回业务错误目录引用与参数,包装后仍输出项目 HTTP 200、数字业务码、提示与 data:null;回滚附加原因、提交内部原因不外泄 | ## 真实 MySQL ```sh python3 scripts/verifyConnector.py --local --gorm --phases --report reports/transactionMySQL.json ``` 使用独立本地 MySQL 8.4 容器,1 CPU / 768 MiB / 128 pids,TLS 与临时随机凭据;不连接接入项目数据库或远程服务器。53 条通过记录(含子用例),耗时 13.2 秒。容器、数据卷、证书与临时消费者已经清理。完整证据见 [transactionMySQL.json](transactionMySQL.json)。 - 正常 Commit 后,另一个连接看到记录;回调失败且真实 Rollback 成功,返回 Work/RolledBack,另一个连接确认没有该记录。 - 在真实驱动 Commit 成功返回后,由测试包装器注入“确认丢失”错误:另一个连接确认记录已经持久化,InTx 返回 Commit/Unknown,没有重试或误报回滚。 - 在真实驱动 Rollback 成功后注入确认错误:库只能返回 Work/Unknown,并保留业务原因与回滚确认错误;不能利用测试已知的数据库状态推断生产结果。 - 这是驱动返回边界的确定性故障注入,不等同于覆盖所有 TCP 断线时序。 - 真实生成项目的配置/TLS/独立连接池/关闭、可选 GORM 事务与连接池归属、后台 drain 后关闭数据库均通过。 - 本轮发现旧 MySQL 验收脚本仍依赖已移除的自动环境覆盖。现已改为测试配置文件显式引用变量,复测通过;没有恢复旧加载模式。 ## 性能 Go 1.27.1、darwin/arm64、Apple M2 Max。使用相同演示驱动和 benchmark,比较 v0.24 的原 InTx 实现与当前实现,每场景三轮、300ms,取中位数。旧实现从提交 `8eddef9cc8e9902150f4f712a40bc761d4350415` 取出,临时 benchmark 文件测后删除。[原始结果](transactionBenchmark.txt)。 | 场景 | 原实现 ns/次 | 当前 ns/次 | 原分配 | 当前分配 | | --- | ---: | ---: | ---: | ---: | | 成功提交 | 617.3 | 587.0 | 392 B / 7 | 392 B / 7 | | 开启失败 | 212.9 | 146.0 | 96 B / 3 | 80 B / 2 | | 回调失败并成功回滚 | 556.5 | 540.9 | 280 B / 6 | 344 B / 7 | | 回调和回滚同时失败 | 681.1 | 732.6 | 416 B / 10 | 344 B / 7 | | 提交结果不确定 | 719.6 | 814.8 | 472 B / 9 | 456 B / 8 | 成功路径没有新增分配。原先直接返回的回调错误现在需要 TxError,增加 64 B / 1 次分配;其他失败路径移除了即时格式化/Join 的部分开销。部分失败路径耗时增加,以上是受 goroutine 调度影响的本机微基准,不含真实数据库网络、SQL 和磁盘耗时,不承诺固定提速比例或服务 QPS。 当前实现复现: ```sh go test ./database -run '^$' -bench '^BenchmarkInTx$' -benchmem -benchtime=300ms -count=3 ``` ## 保证范围 Outcome 只属于当前受管理事务;回调不得自己提交/回滚、执行隐式提交 SQL、把事务交给其他 goroutine。其他连接、独立事务、非事务表、文件和第三方系统的副作用由业务负责。 标准库异步回滚不公开的驱动原因无法还原。只拿到 ErrTxDone 时保守返回 Unknown;直接观察到的回滚失败全部保留。panic/Goexit 保持原有传播,没有普通返回值可携带回滚原因。返回错误的文本/具体最外层类型有变化,调用方使用 errors.Is/As;GORM 自己的 Transaction 不属于本次接口。 ## 远程版本验收 `v0.25.0-preview` 标签固定在 `7a177744ab2bb85f23efc0ec267fd905d349bd4b`,checksum 为 `h1:R1rDYtPBWRfRNHY2Px1gZF3/xpit6Pttd7AvIbMJpKs=`。 - 空 module 缓存安装 CLI,固定远程依赖、无本地 replace,77 项检查通过,耗时 71.93 秒。9 组生成消费者、下载模块 database/config/httpc/copyx/logx/cors/app 的 race、事务示例、生成检查与业务文件保留通过。见 [transactionRemote.json](transactionRemote.json)。 - 独立空缓存下载同一版本,53 条 MySQL 测试记录(含子用例)通过,耗时 28.49 秒。真实 TLS 数据库提交/回滚后的确认丢失、GORM、生成项目与后台 drain 验收通过;独立容器和临时资源已清理。见 [transactionMySQLRemote.json](transactionMySQLRemote.json)。 ```sh python3 scripts/verifyManagedRelease.py --version v0.25.0-preview --report reports/transactionRemote.json python3 scripts/verifyConnector.py --version v0.25.0-preview --gorm --phases --report reports/transactionMySQLRemote.json ``` 发布标签不随验收记录提交移动。