2015-03-10 5 views
0

Мне нужно создать уникальный идентификатор для клиентов, я реализую это, используя 9-значный номер Luhn (девятая цифра - checkdigit), поэтому я могу проверить его подлинность. Цифры, которые я хочу сгенерировать, являются случайными, поэтому я создаю 8-значное число и обрабатываю контрольную цифру, чтобы пойти с ней, это здорово.Блокировка таблицы SQL Server

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

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

+0

Использование NOLOCK таким образом, что сделка не будет влиять друг друга –

ответ

0

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

В конце транзакции вы можете проверить, были ли ошибки при обработке или были ли ваши данные в недопустимом состоянии. Тогда вы бы зафиксировали, если все в порядке или откат, если нет. Но будьте осторожны, оставляя транзакции открытыми! Если вы не совершаете или откатываете транзакцию, затронутые таблицы останутся заблокированными, и все транзакции против этих таблиц будут заблокированы до тех пор, пока вы не совершите или не отмените транзакцию.

Вот пример, который мы надеемся, будет помощь:

DECLARE @Table TABLE 
(
    ID INT IDENTITY PRIMARY KEY 
    ,Luhn INT 
    ,UNIQUE(Luhn) 
) 

DECLARE @MaxTries INT = 10; 
DECLARE @Try INT = 1; 

DECLARE @Luhn INT; 
DECLARE @IsLuhnAvailable BIT = 0; 

BEGIN TRAN; 

WHILE @IsLuhnAvailable = 0 AND @Try <= @MaxTries 
BEGIN 

    SET @Luhn = CHECKSUM(NEWID()); --dbo.GenerateLuhn() 

    SET @IsLuhnAvailable = CASE WHEN EXISTS (SELECT 1 FROM @Table WHERE Luhn = @Luhn) THEN 0 ELSE 1 END; 

    SET @Try +=1; 

END 

IF @IsLuhnAvailable = 0 
BEGIN 
    PRINT 'Luhn could not be generated.' 
    ROLLBACK; 
END 
ELSE 
BEGIN 

    INSERT INTO @Table 
    (
     Luhn 
    ) 
    VALUES 
    (
     @Luhn 
    ) 
    PRINT 'New Luhn was generated: ' + CAST(@Luhn AS VARCHAR) 
    COMMIT; 
END 

SELECT * FROM @Table 
+0

Интересно, спасибо Бреннан. Я думаю, в моем сценарии, если между суффиксами EXISTS и INSERT по совпадению, повторяется двойное значение, то, по крайней мере, я получу ошибку нарушения ограничения, которую я могу обработать на стороне клиента. Так что, наверное, нечего беспокоиться о том, что на самом деле слишком много? –

+0

Любая стратегия, с явной транзакцией или без нее, будет работать. Причина, по которой я заключалась в двух операциях в транзакции, заключалась в том, чтобы избежать ошибки нарушения ограничения, в результате чего вторая совпадающая транзакция будет ждать на первом, а не одновременно. –

+0

Еще одна ошибка при использовании явно определенных транзакций - это возможность создания взаимоблокировок. Чтобы избежать блокировок, попытайтесь свести к минимуму количество операторов и попытайтесь получить доступ к таблицам в стандартном порядке. –

Смежные вопросы