TSQL SELECT然后在一个事务中UPDATE,然后返回SELECT

时间:2009-11-16 17:37:35

标签: sql tsql stored-procedures select coldfusion

我在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个项目的块。这些项目尚未签出,用户之前也无法对其进行评分(因此SELECT中的lock_field为IS NULL和NOT EXISTS语句)。一旦我确定了20个item_id的列表,我就需要更新队列表以将它们标记为已锁定,这样就不会有其他人同时检查它们。我还需要返回item_ids列表。

我认为如果我将它从cftransaction移动到SQL Server端的存储过程,它可能会更好。我只是不确定cftransaction锁定是否以某种方式干扰。我不是TSQL大师,所以一些帮助将不胜感激。

2 个答案:

答案 0 :(得分:12)

使用公用表表达式选择数据,然后从UPDATE语句更新CTE和输出。这样一切都是一个单一的操作:

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;

答案 1 :(得分:2)

对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

这应该确保您的选择项将被锁定,直到更新完成。

编辑:添加了一个输出子句,因为原始问题也想知道哪些行已更新。