Sobes.tech
Back to questions
Senior
3

Как атомарно реализовать проверку доступности и создание заказа при выносе логики в сервис?

Companies where asked
2gis2gis

Answer from AI

sobes.tech AI

Для атомарной проверки доступности и создания заказа в сервисе на Go обычно используют транзакции базы данных. В рамках одной транзакции сначала проверяется доступность (например, наличие товара на складе), затем создаётся заказ. Если что-то идёт не так — транзакция откатывается, что гарантирует консистентность данных.

Пример с использованием базы данных и пакета database/sql:

func CreateOrderIfAvailable(db *sql.DB, productID int, quantity int, userID int) error {
    tx, err := db.Begin()
    if err != nil {
        return err
    }
    defer tx.Rollback()

    var available int
    err = tx.QueryRow("SELECT stock FROM products WHERE id = ? FOR UPDATE", productID).Scan(&available)
    if err != nil {
        return err
    }

    if available < quantity {
        return fmt.Errorf("not enough stock")
    }

    _, err = tx.Exec("UPDATE products SET stock = stock - ? WHERE id = ?", quantity, productID)
    if err != nil {
        return err
    }

    _, err = tx.Exec("INSERT INTO orders (user_id, product_id, quantity) VALUES (?, ?, ?)", userID, productID, quantity)
    if err != nil {
        return err
    }

    return tx.Commit()
}

Здесь FOR UPDATE блокирует строку с товаром, предотвращая гонки при параллельных запросах. Вся логика в сервисе оборачивается в транзакцию, что обеспечивает атомарность операции.