Лучший подход для распределения ключа на несколько таблиц в транзакции - PullRequest
0 голосов
/ 14 февраля 2011

Это тот случай. У меня есть основная таблица с номером счета (int) и много таблиц с соответствующими данными. Когда счет выставляется, я увеличиваю номер счета в основной таблице и затем помещаю дополнительные данные, а также номер счета в остальные таблицы.

Поскольку все находится в транзакции (READ COMMITED), все изменения не записываются физически до тех пор, пока эта транзакция не будет зафиксирована.

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

Если имеется много параллельных длинных счетов (транзакций с большим количеством данных), может быть много повторных попыток.

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

Ответы [ 4 ]

0 голосов
/ 14 февраля 2011

Что ж, если у вас абсолютно не может быть дыр (в соответствии с идентификацией), вам нужно будет заблокировать строку пользовательской таблицы идентификаторов / семени, пока вы не будете на 100% уверены, что все ваши вставки зафиксировали.Однако вам также необходимо убедиться, что любые другие одновременные доступы к этой записи также имеют уровень изоляции SERIALIZABLE.

BEGIN TRAN
SELECT NextId FROM myKeysTable
WITH (XLOCK, SERIALIZABLE)
WHERE myTablePKName = 'SomeId'
...

Это будет удерживать исключительную блокировку строки, предотвращая другие операции чтения (и с SERIALIZABLE).оговорка).

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

Но это звучит не очень масштабируемо / производительно.

0 голосов
/ 14 февраля 2011

сделайте это:

BEGIN TRANSACTION

INSERT INTO YourHeaderTable  (col1, col2,..) values (...)---where PK is identity
SELECT @newID=SCOPE_IDENTITY()

INSERT INTO Table2 VALUES (@newID,...)  --use the @newID from YourHeaderTable  
INSERT INTO Table3 VALUES (@newID,....) --use the @newID from YourHeaderTable  
...

COMMIT

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

0 голосов
/ 14 февраля 2011

Используйте столбец IDENTITY - это гарантирует уникальное значение. И вы можете (если вы используете SQL Server 2005+) использовать предложение OUTPUT исходного запроса INSERT, чтобы зафиксировать значение идентификатора, сгенерированное для строки (строк) вашего счета. Если вы вставляете несколько счетов-фактур, вам нужно захватить дополнительные столбцы из вставки, чтобы однозначно идентифицировать счета-фактуры для вставки связанных строк в другие таблицы.

0 голосов
/ 14 февраля 2011

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

т.е. Предположим, что текущий максимальный счет равен 2, вы вставляете новый, добавляя строку в эту таблицу. Вызов LAST_INSERT_ID() даст вам идентификатор строки, которую вы только что вставили в эту основную таблицу счетов, - 3. Если в то же время начинается другая другая транзакция, он получит число 4. Ваш механизм транзакций достаточно умен, чтобы не дважды назначать идентификатор. Затем вы можете использовать этот идентификатор, чтобы пометить все свои данные во вспомогательных таблицах, не беспокоясь о том, что они будут назначены дважды.

...