下面是一个使用事务的例子:
- 创建一个订单,如果库存够,则更新album表里面库存数量,然后往album_order里插入新行,提交事务。最后返回一个订单ID。
- 如果过程中有失败,则回滚。
// createOrder creates an order for an album and return the new order ID.
func createOrder(ctx context.Context, albumID, quantity, customID int) (int64, error) {
// Create a helper function for preparing failure result.
fail := func(err error) (int64, error) {
return 0, fmt.Errorf("createOrder: %v", err)
}
// Get a Tx for making transaction request.
tx, err := db.BeginTx(ctx, nil)
if err != nil {
fail(err)
}
// Defer a rollback in case anything fails
defer tx.Rollback()
// Confirm the album inventory is enough for the order.
var enough bool
if err = tx.QueryRowContext(ctx, "SELECT (quantity >= ?) FROM album WHERE id = ?", quantity, albumID).Scan(&enough); err != nil {
if err == sql.ErrNoRows {
fail(fmt.Errorf("no such album"))
}
return fail(err)
}
if !enough {
fail(fmt.Errorf("no enough inventory"))
}
// Update the album inventory to remove the quantity in the order.
_, err = tx.ExecContext(ctx, "UPDATE album SET quantity = quantity - ? WHERE id = ?", quantity, albumID)
if err != nil {
fail(err)
}
// Create a new row in the album_order table.
result, err := tx.ExecContext(ctx, "INSERT INTO album_order (album_id, custom_id, quantity, date) values (?, ?, ?, ?)", albumID, customID, quantity, time.Now())
if err != nil {
fail(err)
}
// Get the ID of the order item just created.
orderID, err := result.LastInsertId()
if err != nil {
fail(err)
}
// Commit the transaction.
if err = tx.Commit(); err != nil {
fail(err)
}
// Return the order ID.
return orderID, nil
}