Как мне заблокировать, чтобы избежать дублирования номеров - PullRequest
0 голосов
/ 15 февраля 2011

У меня есть таблица A (SQL Server 2008), которая содержит наборы минимальных и максимальных чисел.В одной из моих хранимых процедур я использую эту таблицу, объединенную с таблицей продуктов B, чтобы найти доступный номер продукта, который находится между min и max, а затем вставляю новый продукт с этим номером продукта.Поэтому я хочу следующий свободный номер, который находится между мин / макс.

Между поиском следующего доступного номера и вставкой строки продукта, я хочу блокировку, чтобы никто не мог найти тот же номер (и дать дубликат).

Как мне думать в этой ситуации?Должен ли я получить блокировку обновления таблицы A, хотя я никогда не изменяю ее?Блокировка должна быть снята после того, как я выполню вставку в таблицу B и транзакция завершится?Будет ли эта блокировка обновления мешать другим транзакциям читать таблицу A?

Редактировать: таблица min / max является таблицей для различных серий продуктов.В зависимости от того, какую серию вы хотите, я хочу попробовать найти номер в этой последовательности.Productnr не является уникальным, однако можно сделать его уникальным в сочетании со вторым столбцом.Упрощенный sp:

CREATE PROCEDURE [dbo].[InsertProduct]
(
@Param1 int,
@Param2 bit,
...
@Param20 int) AS 
BEGIN
    DECLARE @ProductNr int
    --Here I do a query to determine which ProductNr I should have. Checking that the number is between max/min in the series and that no other product has this productnr.
    --Now insert the row
    INSERT INTO Products VALUES (@Param1, @ProductNr, ...., @Param2
END

Ответы [ 2 ]

1 голос
/ 15 февраля 2011

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

Несмотря на это, тактика, которую я использовал в прошлом, состоит в том, чтобы попытаться обернуть все в одно утверждение - здесь это будет ВСТАВКА. Каждый оператор SQL де-факто обернут в свою собственную неявную транзакцию (это атомарность, что означает «A» в ACID славы свойств реляционной базы данных). В псевдо-коде это будет выглядеть примерно так:

INSERT MyTable (Id, Plus, Other, Columns)
 select CalcForNewId, Plus, Other, Columns
 from [what may be a pertty convoluted query to determine the "next" valid Id]

Это работает только в том случае, если вы можете написать свою бизнес-логику в виде одного разумного запроса (где «разумный» означает, что он не блокирует, не блокирует и не блокирует блокировку ни текущего, ни любого другого пользователя в течение неоправданного периода времени). Это может быть довольно сложный заказ, но я бы взял на себя необходимость писать сложный код BEGIN TRANSACTION / COMMIT / ROLLBACK, смешанный с блоками TRY ... CATCH, в любой день. (Это, конечно, сработает, и я соответственно проголосовал за @ Scott Bruns.)

1 голос
/ 15 февраля 2011

Просто вставьте следующий номер в таблицу B. Если он зафиксирован, вы можете его использовать. Если вы получили нарушение ключа, это означает, что другой процесс только что ввел новый номер. В этом случае увеличьте новый номер и попробуйте снова.

База данных автоматически обработает для вас валюту. Ручная блокировка не требуется.

...