2010-04-28 3 views
3

Я пишу небольшое программное обеспечение, которое должно вставлять записи в базу данных, используемую коммерческим приложением. Уникальные первичные ключи (ids) в соответствующей таблице (таблицах) являются последовательными, но, похоже, не настроены на «auto increment». Таким образом, я предполагаю, что мне нужно будет найти самый большой идентификатор, увеличить его и использовать это значение для записи, которую я вставляю.Уровень изоляции транзакции, необходимый для безопасного увеличения идентификаторов

В псевдокоде для краткости:

id = select max(id) from some_table 
id++ 
insert into some_table values(id, othervalues...) 

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

Кроме того, это, как правило, правильный способ решения проблемы? Есть ли другие способы сделать это?

ответ

2

Один из способов сделать это было бы объединить ваши первые две строки в вставки заявления:

INSERT INTO Some_Table ЗНАЧЕНИЯ ((Выберите Max (ID) + 1 из Some_Table), Othervalues ​​...)

или

INSERT INTO Some_Table вЫБОР st2.id, Othervalues ​​ оТ (выбрать макс (ID) +1 от Some_Table) ST2

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

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

+0

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

+0

Я не уверен, что ваше редактирование имело смысл ...? По крайней мере, я не понимаю синтаксис ... и работала первая версия. :) –

+0

Подкатил его обратно и включил оба, так как первая версия работала для вас :) –

0

попробовать это (используя синтаксис SQL Server):

INSERT INTO some_table 
     (id, othervalues...) 
    SELECT 
     ISNULL(max(id),0)+1, othervalues... 
     from some_table WITH (UPDLOCK, HOLDLOCK) 
     WHERE ... 
0

Мы решали подобную проблему для обычно последовательного (но иногда могут быть перезаписаны и не уникальный) номер документа, используя отдельную таблицу. Идея SQL:

Declare @docno Int 
Begin Tran 
Select @docno=lastval+1 From docnotable With(Updlock) Where doctype='xyz' 
Update docnotable Set [email protected] Where doctype='xyz' 
... do whatever you need ... 
Commit Tran 
Смежные вопросы