Скажімо, у вас є такий код (будь ласка, ігноруйте, що це жахливо):
BEGIN TRAN;
DECLARE @id int
SELECT @id = id + 1 FROM TableA;
UPDATE TableA SET id = @id; --TableA must have only one row, apparently!
COMMIT TRAN;
-- @id is returned to the client or used somewhere else
На мій погляд, це НЕ належним чином керувати сумісністю. Тільки тому, що у вас є транзакція, це не означає, що хтось ще не прочитає те саме значення, яке ви робили, перш ніж потрапити до вашої заяви про оновлення.
Тепер, залишаючи код таким, який є (я розумію, що це краще обробляється як одне твердження або ще краще, використовуючи стовпчик з автоматичним підвищенням / ідентифікацією), які є безпечними способами, щоб змусити його правильно обробляти параметри та запобігати перегоновим умовам, які дозволяють двом клієнтам отримати однаковий значення id?
Я майже впевнений, що додавання WITH (UPDLOCK, HOLDLOCK)
до SELECT зробить трюк. SERIALIZABLE рівень ізоляції транзакцій буде схоже на роботу, а так як він заперечує , хто -то ще , щоб читати те , що ви зробили , поки тран не закінчиться ( UPDATE :. Це невірно відповідь знайомства Мартіна). Це правда? Вони працюватимуть однаково добре? Чи один віддає перевагу іншому?
Уявіть, що ви робите щось більш законне, ніж оновлення ID - деякий розрахунок, заснований на прочитаному, який потрібно оновити. Можливо, буде задіяно багато таблиць, деякі з яких ви будете писати, а інші не будете. Яка тут найкраща практика?
Написавши це запитання, я вважаю, що підказки щодо блокування є кращими, оскільки тоді ви фіксуєте лише потрібні вам таблиці, але я вдячний для будь-кого.
PS І ні, я не знаю найкращої відповіді і дійсно хочу краще зрозуміти! :)
update
що може базуватися на застарілих даних? Якщо останнє, ви можете використовуватиrowversion
стовпчик, щоб перевірити, чи рядок, що підлягає оновленню, не змінено з моменту його читання.