Sobes.tech
Назад к вопросам
Senior
4

Ты работал с транзакциями на уровне бизнес-процессов — SELECT FOR UPDATE, rollback при падении внешнего API?

Компании, где спрашивали
Штрафов нет

Ответ от нейросети

sobes.tech AI

Да, работал с транзакциями на уровне бизнес-процессов в Go. Использовал SELECT FOR UPDATE для блокировки строк в базе данных, чтобы избежать гонок при параллельных операциях. Например, при резервировании товара в заказе сначала делал выборку с блокировкой, затем обновлял количество, и только после успешного взаимодействия с внешним API подтверждал транзакцию.

Если внешний API падал, то вызывал rollback транзакции, чтобы не сохранить изменения в базе и не оставить систему в неконсистентном состоянии.

Пример с использованием database/sql и PostgreSQL:

ctx := context.Background()
tx, err := db.BeginTx(ctx, nil)
if err != nil {
    return err
}

// Блокируем строку
row := tx.QueryRowContext(ctx, "SELECT quantity FROM products WHERE id=$1 FOR UPDATE", productID)
var quantity int
if err := row.Scan(&quantity); err != nil {
    tx.Rollback()
    return err
}

if quantity < needed {
    tx.Rollback()
    return errors.New("not enough stock")
}

// Вызов внешнего API
if err := callExternalAPI(); err != nil {
    tx.Rollback()
    return err
}

// Обновляем количество
_, err = tx.ExecContext(ctx, "UPDATE products SET quantity = quantity - $1 WHERE id = $2", needed, productID)
if err != nil {
    tx.Rollback()
    return err
}

return tx.Commit()

Такой подход гарантирует атомарность бизнес-операции и согласованность данных.