数据库 SQL 事务

启动事务

bun.Txsql.Tx 的一个薄包装器。除了 sql.Tx 提供的功能外,bun.Tx 还支持 查询钩子 并提供帮助程序来构建查询。

type Tx struct {
	*sql.Tx
	db *DB
}

要启动事务

tx, err := db.BeginTx(ctx, &sql.TxOptions{})

要提交/回滚事务

err := tx.Commit()

err := tx.Rollback()

在事务中运行查询

就像使用 bun.DB 一样,您可以使用 bun.Tx 来运行查询

res, err := tx.NewInsert().Model(&models).Exec(ctx)

res, err := tx.NewUpdate().Model(&models).Column("col1", "col2").Exec(ctx)

err := tx.NewSelect().Model(&models).Limit(100).Scan(ctx)

RunInTx

Bun 提供 RunInTx 帮助程序,这些帮助程序在事务中运行提供的函数。如果函数返回错误,则回滚事务。否则,提交事务。

err := db.RunInTx(ctx, &sql.TxOptions{}, func(ctx context.Context, tx bun.Tx) error {
    _, err := tx.Exec(...)
    return err
})

IDB 接口

Bun 提供 bun.IDB 接口,因此相同的方法可以与 *bun.DBbun.Txbun.Conn 一起使用。以下 示例在新窗口中打开 演示了 InsertUser 如何使用 bun.IDB 来支持事务

// Insert single user using bun.DB.
err := InsertUser(ctx, db, user1)

// Insert several users in a transaction.
err := db.RunInTx(ctx, nil, func(ctx context.Context, tx bun.Tx) error {
    if err := InsertUser(ctx, tx, user1); err != nil {
        return err
    }
    if err := InsertUser(ctx, tx, user2); err != nil {
        return err
    }
    return nil
})

func InsertUser(ctx context.Context, db bun.IDB, user *User) error {
	_, err := db.NewInsert().Model(user).Exec(ctx)
	return err
}

PostgreSQL 咨询锁

您可以使用以下代码获取 PostgreSQL 咨询锁

err := db.RunInTx(ctx, nil, func(ctx context.Context, tx bun.Tx) error {
    if _, err := tx.ExecContext(ctx, "SELECT pg_advisory_xact_lock(1)"); err != nil {
        return err
    }
    if _, err := db.NewSelect().ColumnExpr("pg_advisory_xact_lock(2)").Exec(ctx); err != nil {
        return err
    }
    return nil
})