Как избежать одновременной записи в строку с помощью Slick? - PullRequest
0 голосов
/ 20 сентября 2019

У меня есть следующая таблица:

case class Project(id: Int, name: String, locked: Boolean)

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

Мой способ прямо сейчас - установить locked = true для проекта всякий раз, когда задание начинается, и если пользователь (злонамеренный или другой) пытается запустить второе задание, пока locked = true, он должен проверить, является ли locked уже верным, и если это так, он должен ответить сообщением об ошибке «Пожалуйста, подождите» или что-то подобное.

Я думаю, что мне нужно сделать это с помощью транзакций, поэтому гонкиусловия / параллельные запросы не будут работать, и злонамеренный пользователь не сможет отправить одновременные запросы и запустить несколько заданий, потому что все увидели locked = false (как они запускались одновременно)

Как я могу это сделатьс сликом?Моя текущая попытка выглядит следующим образом:

def lock(id: Long): Future[Int] = {
        val select = (for {p <- projects if p.id === id && p.locked === false} yield l.locked)
        val q = select.update(true).transactionally //attempting to use transactions
        db.run(q)
    }

Я полагаю, db.run вернет количество обновленных строк, а если условие p.locked === false не выполнится, то количество обновленных строк будет равно 0, иЯ мог бы использовать это, чтобы определить, был ли проект успешно заблокирован.И, возможно, .transactionally должен выполнять этот запуск в транзакциях, чтобы одновременные запросы не были проблемой.

Верны ли мои предположения / рассуждения здесь?Есть ли лучший способ сделать это?

1 Ответ

1 голос
/ 20 сентября 2019

Значение .transactionally здесь зависит от того, какую базу данных вы используете.

Без указания чего-либо другого, таким образом, вы используете уровень изоляции по умолчанию для транзакции, предлагаемой вашей БД, например,Если вы используете Postgres, уровень будет READ COMMITTED, что означает, что при двух одновременных транзакциях одна может увидеть данные, переданные другой, до того, как она закончится.

Я предлагаю вам всегда указывать изоляциюУровень с .transactionally.withTransactionIsolation(transactionLevel), чтобы избежать проблем параллелизма

...