使用内存数据库或sqlmock测试Go事务。1. 用SQLite测试回滚:插入数据后调用Rollback,验证数据未保存;2. 测试Commit后数据持久化;3. 模拟错误触发Rollback,确保无脏数据;4. 用sqlmock模拟事务流程,验证执行顺序。

在 Go 语言中测试数据库事务的关键在于验证事务的提交与回滚行为是否符合预期。我们通常使用 sql.Tx 来管理事务,并借助测试工具模拟真实场景,确保数据一致性。下面介绍如何有效测试事务中的回滚和提交逻辑。
推荐使用支持事务的内存数据库(如 SQLite)来加速测试并避免依赖外部环境。
注意:MySQL 和 PostgreSQL 的驱动也可以配合 Docker 容器使用,但 SQLite 更轻量,适合单元测试。示例代码:
package main
import (
"database/sql"
"log"
"testing"
_ "github.com/mattn/go-sqlite3"
)
func setupTestDB() *sql.DB {
db, err := sql.Open("sqlite3", ":memory:")
if err != nil {
log.Fatal(err)
}
_, err = db.Exec(`CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)`)
if err != nil {
log.Fatal(err)
}
return db
}
func insertUser(tx *sql.Tx, name string) error {
_, err := tx.Exec("INSERT INTO users (name) VALUES (?)", name)
return err
}
编写测试函数验证回滚:
立即学习“go语言免费学习笔记(深入)”;
func TestTransaction_Rollback(t *testing.T) {
db := setupTestDB()
defer db.Close()
tx, _ := db.Begin()
err := insertUser(tx, "Alice")
if err != nil {
t.Fatal(err)
}
// 不调用 Commit,直接 Rollback
tx.Rollback()
var count int
err = db.QueryRow("SELECT COUNT(*) FROM users WHERE name = ?", "Alice").Scan(&count)
if err != nil {
t.Fatal(err)
}
if count != 0 {
t.Errorf("expected no user after rollback, but got %d", count)
}
}
测试提交后数据应持久化到数据库。
func TestTransaction_Commit(t *testing.T) {
db := setupTestDB()
defer db.Close()
tx, _ := db.Begin()
err := insertUser(tx, "Bob")
if err != nil {
t.Fatal(err)
}
err = tx.Commit()
if err != nil {
t.Fatal(err)
}
var count int
err = db.QueryRow("SELECT COUNT(*) FROM users WHERE name = ?", "Bob").Scan(&count)
if err != nil {
t.Fatal(err)
}
if count != 1 {
t.Errorf("expected 1 user after commit, but got %d", count)
}
}
实际业务中常因操作失败需回滚事务。可在插入非法数据时测试自动回滚行为。
例如:插入违反约束的数据(如空名称),然后回滚。
func TestTransaction_ErrorHandling(t *testing.T) {
db := setupTestDB()
defer db.Close()
tx, _ := db.Begin()
err := insertUser(tx, "")
if err != nil {
tx.Rollback() // 显式回滚
} else {
tx.Commit()
}
var count int
err = db.QueryRow("SELECT COUNT(*) FROM users WHERE name = ''").Scan(&count)
if err != nil {
t.Fatal(err)
}
if count != 0 {
t.Errorf("expected no empty-name user after rollback, but got %d", count)
}
}
这种写法能确保即使插入失败,也不会留下脏数据。
对于不希望真正连接数据库的场景,可用 sqlmock 库模拟事务行为。
安装:
go get github.com/DATA-DOG/go-sqlmock
示例测试:
import (
"testing"
"github.com/DATA-DOG/go-sqlmock"
)
func TestWithSqlMock(t *testing.T) {
db, mock, err := sqlmock.New()
if err != nil {
t.Fatalf("failed to open sqlmock: %v", err)
}
defer db.Close()
mock.ExpectBegin()
mock.ExpectExec("INSERT INTO users").WillReturnResult(sqlmock.NewResult(1, 1))
mock.ExpectRollback() // 假设我们回滚
tx, _ := db.Begin()
tx.Exec("INSERT INTO users (name) VALUES (?)", "Charlie")
tx.Rollback()
if err := mock.ExpectationsWereMet(); err != nil {
t.Errorf("unfulfilled expectations: %s", err)
}
}
这种方式适合集成测试或服务层逻辑验证,无需真实数据库。
基本上就这些。通过内存数据库或 mock 工具,可以完整覆盖事务的提交、回滚和异常处理路径,保证业务逻辑正确性。
以上就是Golang 如何测试数据库事务_Golang 事务回滚与提交行为验证的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号