Home  >  Article  >  Backend Development  >  How to use transactions in Golang?

How to use transactions in Golang?

WBOY
WBOYOriginal
2024-06-04 12:13:56858browse

In Go, you can use the Tx type for transaction operations. To start a transaction, use db.Begin(). In the transaction block, database operations such as queries and updates are performed. After successful execution, use tx.Commit() to commit the transaction. In practice, transactions ensure consistency for concurrent operations, such as updating inventory and creating orders simultaneously.

如何在 Golang 中使用事务?

How to use transactions in Go?

In Go, a transaction is a collection of atomic operations that either all succeed or all fail. They are used to ensure the integrity of database operations, especially in situations where multiple concurrent operations could cause data corruption.

Transactions in Go are represented by the Tx type in database/sql. To start a transaction, do the following:

tx, err := db.Begin()
if err != nil {
    return fmt.Errorf("failed to begin transaction: %w", err)
}

In the transaction block, you can perform any database operation. For example, the following code selects a record from a table and updates it with a new value:

var id, version int
if err := tx.QueryRow("SELECT id, version FROM example WHERE name = ?", "foo").Scan(&id, &version); err != nil {
    return fmt.Errorf("failed to select: %w", err)
}

result, err := tx.Exec("UPDATE example SET version = ? WHERE id = ? AND version = ?", version+1, id, version)
if err != nil {
    return fmt.Errorf("failed to update: %w", err)
}

After all operations have been successfully performed, you can use tx.Commit() to commit the transaction:

if err := tx.Commit(); err != nil {
    // 放弃事务
    if err := tx.Rollback(); err != nil {
        return fmt.Errorf("failed to rollback transaction: %w", err)
    }
    return fmt.Errorf("failed to commit transaction: %w", err)
}

Practical Case

Consider an online store database, which includes a products table and an orders table. We want to create a transaction to do the following:

  1. Check if the product has enough stock.
  2. If there is stock, the stock of the product is deducted and an order is created.
func CreateOrder(db *sql.DB, productID int, quantity int) error {
    tx, err := db.Begin()
    if err != nil {
        return fmt.Errorf("failed to begin transaction: %w", err)
    }

    var stock int
    if err := tx.QueryRow("SELECT stock FROM products WHERE id = ?", productID).Scan(&stock); err != nil {
        return fmt.Errorf("failed to select: %w", err)
    }

    if stock < quantity {
        return tx.Rollback() // 放弃事务,因为没有足够的库存
    }

    if _, err := tx.Exec("UPDATE products SET stock = ? WHERE id = ?", stock-quantity, productID); err != nil {
        return fmt.Errorf("failed to update: %w", err)
    }

    if _, err := tx.Exec("INSERT INTO orders (product_id, quantity) VALUES (?, ?)", productID, quantity); err != nil {
        return fmt.Errorf("failed to insert: %w", err)
    }

    if err := tx.Commit(); err != nil {
        return fmt.Errorf("failed to commit transaction: %w", err)
    }

    return nil
}

By using transactions, we ensure that the store's inventory is always accurate, even if there are multiple concurrent orders trying to subtract inventory from the same product.

The above is the detailed content of How to use transactions in Golang?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn