Необходимость параллелирования базы данных при добавлении строк - лучшая практика?

Я работаю с приложением, которое добавляет новую строку в базу данных, основываясь на последней строке, отвечающей определенным критериям. Существует ли стандартный шаблон для решения этой проблемы, или мне просто нужно заблокировать таблицу?

Вот чрезмерно упрощенная визуализация:

A1
A2
A3
B1
B2

Используя визуализацию выше, веб-страница загружает самое высокое значение «B», которое равно «2». Затем через некоторое время он хочет вставить B3, следующую запись в серии. Тем не менее, он должен проверить, чтобы кто-то еще не делал то же самое.

Как я уже упоминал, я знаю, что могу прочитать значение expeIDENTITYTY внутри транзакции, или я мог бы заблокировать таблицу или, возможно, даже последнюю строку. Я спрашиваю, есть ли рекомендуемая стратегия.

sql,sql-server,concurrency,

2

Ответов: 10


1

Это выглядит как классический случай необходимости оператора, который я всегда хочу: «убедитесь, что кортеж, удовлетворяющий этим условиям, существует и дайте мне ключ».

В моем случае это обычно просто: «У меня есть этот номер кредитной карты и срок действия, что для этого важно?» Мне все равно, если это уже в БД или нет (на самом деле, приложение не должно быть в состоянии сказать, для целей безопасности), я просто хочу, чтобы идентификатор был там, если он есть, или я хочу, чтобы это было если это не так, и получить новый идентификатор для этого создания.

Насколько я могу судить по текущей технологии СУБД, вам необходимо заблокировать таблицу, потому что вы должны принять решение о том, следует ли вставлять или не основываться на том, что уже существует. Однако я бы хотел, чтобы это было лучшее решение.


1

Концептуально, если я понимаю накопление разъяснений, ситуация заключается в том, что вы хотите записать, что элемент вступил в новое состояние - часть оборудования достигла определенного шага. И вы хотите сделать это, основываясь на увеличении шага, который, как считается, сейчас находится.

Я бы повторил это, возможно, более управляемым и недвусмысленным. Можете ли вы просто вставить запись, утверждающую, что машина наблюдается в состоянии, с меткой времени?

Вывод текущего шага из предыдущей информации (которая может быть неадекватно известна) представляется рискованной, особенно если это простой расчет итераций, который может происходить от 0 до n раз по обстоятельствам.

OTOH, если это временное наблюдение за фактическим состоянием, то оно самокорректируется (неважно, какое состояние вы считали ранее), и несколько утверждений не вызывают проблем.

Можете ли вы восстановить логику таким образом, основываясь на существующих формах (или, может быть, небольшой модификации формы или сетевого устройства или чего-то еще)? Есть ли пользователь или IP-адрес и т. Д., Связанный с заданным шагом подэтапа? Имеются ли связанные транзакции, которые действительны только в том случае, если они находятся на шаге или подмножестве шагов?


1

См. Эту запись в своем блоге о том, как это сделать, используя рекурсивный CTEи сингл :UPDATE mytable SET step = step + 1

Обновить:

Если проблема заключается в создании оборудования на следующем этапе, то, вероятно, лучше использовать абсолютное значение вместо относительного.

Помните предыдущее значение шага в переменной (в самой странице или на стороне сервера) и просто обновляйте ее новым значением переменной.

Вместо этого:

last_update

использовать это:

SELECT  last_update
INTO    @lastupdate
FROM    mytable
WHERE   item_id = @id

UPDATE  mytable
SET     step = @nextstep
WHERE   item_id = @id
        AND last_update = @lastupdate

Вы также можете добавить автоинкрементное IDENTITYполе в столбец, чтобы убедиться, что вы обновляете столбец, который не обновлялся с момента загрузки вашей страницы:

ID

Обновление 2 :

Если вы используете связанный список состояний (т. Е. Вы не обновляете, а вставляете новые состояния), просто отметьте столбец IDENTITYи вставьте IDпредыдущее состояние:

item_id  step_id  prev_step_id
1        10232     0
1        12123     10232

, make step_idи prev_step_id WITH q ( item_id , step_id , step_no ) AS ( SELECT item_id , step_id , 1 FROM mytable WHERE item_id = 1 AND prev_step_id = 0 UNION ALL SELECT q . item_id , m . step_id , q . step_no + 1 FROM q JOIN mytable m ON m . item_id = q . item_id m . prev_step_id = q . step_id ) SELECT * FROM q и запрос выглядит так:

UNIQUE

Если два человека хотят вставить две записи, тогда UNIQUEограничение на prev_step_idwil fire и последнюю вставку не удастся.


0

Это идеальный случай для использования очереди. Попробуйте Message Broker.


0

Просто заверните его в одно и то же утверждение. Первая вставка нового значения (2) будет успешной, вторая добавит нулевые строки.

create table t1 (i int)
insert t1 values (1)

insert t1 (i)
    select 2 where exists (select max(i) from t1 having max(i) = 1)

insert t1 (i)
    select 2 where exists (select max(i) from t1 having max(i) = 1)
SQL, SQL-сервер, параллелизм,
Похожие вопросы