Sobes.tech
Senior

Zadatak za projektovanje: postoji sistem za grupe za brzo reagovanje. Kada stigne signal, tri grupe istovremeno reaguju. Potrebno je poslati samo jednu grupu. Kako to uraditi na nivou transakcija u bazi podataka?

sobes.tech АИ

Одговор од АИ

Для решения задачи с одновременным откликом нескольких групп и выбором только одной на уровне транзакций в базе данных можно использовать механизм блокировок и уникальных ограничений.

Подход:

  1. Создайте таблицу, например, signal_assignments, где хранится информация о том, какая группа назначена на сигнал.
  2. При получении сигнала каждая группа пытается вставить запись с уникальным ключом по сигналу (например, signal_id с уникальным индексом).
  3. Первая транзакция, которая успешно вставит запись, «захватывает» сигнал.
  4. Остальные транзакции при попытке вставки получат ошибку уникального ограничения и должны откатиться или повторить попытку.

Пример на SQL:

CREATE TABLE signal_assignments (
    signal_id UUID PRIMARY KEY,
    group_id UUID NOT NULL
);

При обработке сигнала в транзакции:

BEGIN;
INSERT INTO signal_assignments(signal_id, group_id) VALUES (:signal_id, :group_id);
COMMIT;

Если вставка не удалась из-за уже существующей записи, значит сигнал уже назначен другой группе.

В Go с использованием транзакций:

func assignGroup(db *sql.DB, signalID, groupID string) error {
    tx, err := db.Begin()
    if err != nil {
        return err
    }
    defer tx.Rollback()

    _, err = tx.Exec(`INSERT INTO signal_assignments(signal_id, group_id) VALUES ($1, $2)`, signalID, groupID)
    if err != nil {
        // Ошибка уникального ограничения — сигнал уже назначен
        return err
    }

    return tx.Commit()
}

Таким образом, на уровне базы данных гарантируется, что только одна группа будет назначена на сигнал, несмотря на одновременные попытки.