TSQL SELECT, затем ОБНОВИТЬ в одной транзакции, затем вернуть SELECT - PullRequest
6 голосов
/ 16 ноября 2009

У меня действительно проблемы с запросом в моем приложении ColdFusion (добавлено в MS SQL 2008). Я продолжаю получать сообщения об ошибках блокировки транзакций в БД:

<code>
<cftransaction>
   <cfquery name="selectQuery">
      SELECT TOP 20 item_id, field2, field3
      FROM Table1
      WHERE subject_id = #subject_ID# AND lock_field IS NULL AND
            NOT EXISTS (SELECT * FROM Table2 WHERE Table2.user_ID = #user_ID# Table1.item_id = Table2.item_id)
   </cfquery>

   <cfquery name="updateQuery">
      UPDATE Table1
      SET lock_field = 1, locked_by = #user_ID#
      WHERE Table1.item_id IN (#ValueList(selectQuery.item_id#)
   </cfquery>
</cftransaction>
</code>

По сути, у меня есть таблица (Table1), которая представляет большую очередь ожидающих элементов. Пользователи «оформляют покупки», чтобы дать им оценку. Только один пользователь может получить товар за один раз. Мне нужно запросить блок из 20 предметов одновременно для данного пользователя. Эти элементы уже не могут быть извлечены, и пользователь уже не мог их забить ранее (следовательно, оператор lock_field IS NULL и NOT EXISTS в SELECT). После того как я определил список из 20 item_ids, мне нужно обновить таблицу очередей, чтобы пометить их как заблокированные, чтобы никто больше не проверял их одновременно. Мне также нужно вернуть этот список item_ids.

Я думал, что это могло бы работать лучше, если бы я переместил это из cftransaction в хранимый процесс на стороне SQL Server. Я просто не уверен, что блокировка cftransaction как-то мешает. Я не гуру TSQL, поэтому некоторая помощь приветствуется.

Ответы [ 2 ]

12 голосов
/ 16 ноября 2009

Используйте общее табличное выражение для выбора данных, затем обновите CTE и выведите из оператора UPDATE. Таким образом, все это одна операция:

with cte as (
 SELECT TOP 20 item_id, field2, field3 
 FROM Table1 WITH (ROWLOCK, UPDLOCK)
 WHERE subject_id = #subject_ID# 
 AND lock_field IS NULL 
 AND NOT EXISTS (
   SELECT * FROM Table2 
   WHERE Table2.user_ID = #user_ID# AND Table1.item_id = Table2.item_id))
update cte   
 SET lock_field = 1, locked_by = #user_ID# 
 output inserted.item_id;
2 голосов
/ 16 ноября 2009

Немного зная (читай: что-нибудь) о PHP, но имея некоторый опыт работы с TSQL, вы можете подумать об изменении своего запроса на что-то вроде этого:

update TABLE1 set LOCK_FIELD = 1
output inserted.item_id, inserted.OtherInterestingColumnsGoHere
from (select top 20 item_id from TABLE1(holdlock) ) as a
where a.item_id = table1.item_id

Это должно гарантировать, что выбранные вами элементы будут заблокированы до завершения обновления.

edit: добавлено предложение вывода, так как исходный вопрос также хотел знать, какие строки были обновлены.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...