у нас есть некоторые постоянные данные в приложении, которые запрашиваются с сервера, а затем хранятся в базе данных, поэтому мы можем отслеживать дополнительную информацию. Поскольку мы не хотим запрашивать, когда объект используется в памяти, мы делаем select for update
, так что другие потоки, которые хотят получить одни и те же данные, будут заблокированы.
Я не уверен, как select for update
обрабатывает несуществующие строки. Если строка не существует, а другой поток пытается сделать еще один select for update
в той же строке, будет ли этот поток блокироваться до тех пор, пока другая транзакция не завершится, или не получит ли пустый набор результатов? Если он получает только пустой набор результатов, есть ли способ его блокировать, например, сразу же вставив недостающую строку?
EDIT:
Поскольку было замечание, что мы могли бы запереть слишком много, вот еще несколько подробностей о конкретном использовании в нашем случае. В сокращенном псевдокоде наш программный поток выглядит следующим образом:
d = queue.fetch();
r = SELECT * FROM table WHERE key = d.key() FOR UPDATE;
if r.empty() then
r = get_data_from_somewhere_else();
new_r = process_stuff( r );
if Data was present then
update row to new_r
else
insert new_r
Этот код запускается в нескольких потоках, и данные, полученные из очереди, могут относиться к одной и той же строке в базе данных (следовательно, к блокировке). Однако, если несколько потоков используют данные, которые нуждаются в одной и той же строке, то эти потоки должны быть секвентизированы (порядок не имеет значения). Однако эта секвенциализация терпит неудачу, если строка отсутствует, потому что мы не получаем блокировку.
EDIT:
На данный момент у меня есть следующее решение, которое кажется уродливым взломом для меня.
select the data for update
if zero rows match then
insert some dummy data // this will block if multiple transactions try to insert
if insertion failed then
// somebody beat us at the race
select the data for update
do processing
if data was changed then
update the old or dummy data
else
rollback the whole transaction
Я не уверен на 100%, однако это фактически решает проблему, и это решение не кажется хорошим. Поэтому, если кто-то должен предложить что-то более удобное, это будет здорово.