Model
objects can also be created through the TX
transaction interface. The functionality of a Model
object created through a transaction object is the same as that of one created through a DB
database object, except that the former's operations are based on transactions. Once the transaction is committed or rolled back, the corresponding Model
object cannot be used further; otherwise, an error will be returned. Because the TX
interface cannot be reused, a transaction object corresponds to a single transaction process and ends after Commit
/Rollback
.
This chapter provides a simple introduction to transaction handling methods involved in chaining operations. For more detailed information, please refer to the ORM - Transaction chapter.
Example 1: Using Transaction
To facilitate transaction operations, gdb
provides a closure operation for transactions, implemented through the Transaction
method, which is defined as follows:
func (db DB) Transaction(ctx context.Context, f func(ctx context.Context, tx TX) error) (err error)
If the error
returned by the given closure method is nil
, the Commit
operation is automatically executed after the closure finishes execution; otherwise, it automatically performs a Rollback
.
If a panic
occurs within the closure operation, the transaction will also be rolled back.
func Register() error {
return g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
var (
result sql.Result
err error
)
// Insert basic user data
result, err = tx.Table("user").Insert(g.Map{
"name": "john",
"score": 100,
//...
})
if err != nil {
return err
}
// Insert user detail data, utilizing the user uid from the previous insertion
result, err = tx.Table("user_detail").Insert(g.Map{
"uid": result.LastInsertId(),
"phone": "18010576258",
//...
})
return err
})
}
Example 2: Using TX
Chaining Operations
We can also switch the bound transaction object within chaining operations using the TX
method. Multiple chaining operations can bind to the same transaction object, executing the corresponding chaining operations within that transaction object.
func Register() error {
var (
uid int64
err error
)
tx, err := g.DB().Begin()
if err != nil {
return err
}
// Validate the return value upon method exit,
// If successful, execute tx.Commit() to commit,
// Otherwise, execute tx.Rollback() to roll back.
defer func() {
if err != nil {
tx.Rollback()
} else {
tx.Commit()
}
}()
// Insert basic user data
uid, err = AddUserInfo(tx, g.Map{
"name": "john",
"score": 100,
//...
})
if err != nil {
return err
}
// Insert user detail data, using the user uid from the previous insertion
err = AddUserDetail(tx, g.Map{
"uid": uid,
"phone": "18010576259",
//...
})
return err
}
func AddUserInfo(tx gdb.TX, data g.Map) (int64, error) {
result, err := g.Model("user").TX(tx).Data(data).Insert()
if err != nil {
return 0, err
}
uid, err := result.LastInsertId()
if err != nil {
return 0, err
}
return uid, nil
}
func AddUserDetail(tx gdb.TX, data g.Map) error {
_, err := g.Model("user_detail").TX(tx).Data(data).Insert()
return err
}