Вы, вероятно, можете сделать это на SQL Сервере, хотя база данных определенно не лучшее место для реализации таких вещей. Требуется немного изменить запрос, добавив несколько подсказок, таких как:
SELECT TOP 1 *
FROM table_name with (xlock, holdlock, rowlock, readpast)
WHERE last_match >= DATEADD(hour, -3, GETDATE()) and **some_other_conditions**
ORDER BY last_match desc;
Первые 3 подсказки гарантируют, что строка, выбранная одним соединением, останется недоступной для других, пока его транзакция не будет зафиксирована. Подсказка readpast
позволяет запросу пропускать строки, заблокированные другими транзакциями, и продолжать идти в поисках подходящего соответствия, не дожидаясь снятия блокировок.
Пара предостережений, которые вам нужно имейте в виду:
- Вся единица работы должна быть выполнена в рамках одной транзакции на стороне клиента с использованием одного и того же соединения с базой данных. Убедитесь, что у вас не более одного соединения на один поток приложения, и что соединения не распределяются между потоками;
- Подсказка
readpast
позволяет пропускать блокировки на уровне строки, но не пропускает страницу замки. Вам нужно будет как-то убедиться, что на эту таблицу не будут наложены никакие блокировки страниц, не говоря уже о блокировках разделов или таблиц. - Если у вас есть какое-то количество одновременных соединений, о которых стоит упомянуть, вы можете легко исчерпать буфер блокировки , который не настраивается в SQL Server. К счастью, компонент Database Engine может динамически наращивать его при необходимости, но вы все равно можете столкнуться с неожиданными ситуациями, когда чрезмерная конкуренция за блокировку приведет к заметному снижению производительности.
- Если в вашей базе данных включен RCSI, вам необходимо добавить
readcommittedlock
подсказка к вашему запросу. Без него блокировки ничего бы не значили, так как другие соединения смогут читать «предыдущие версии» выбранных совпадений (которые в этом случае будут иметь те же данные, что и строка, выбранная другим потоком).
Если вы собираетесь использовать этот подход, обязательно выполните полномасштабное стресс-тестирование, прежде чем запускать его в производство.