2009-11-16 1 views
6

내 ColdFusion 응용 프로그램 (MS SQL 2008에 백엔드)에서 쿼리에 문제가 있습니다. 나는이 거래에 DB 교착 상태 오류가 계속 :TSQL SELECT를 한 트랜잭션에서 업데이트 한 다음 SELECT를 반환합니다.

<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> 

Bascially, 나는 테이블 대기 항목의 큰 큐를 나타냅니다 (표 1)를 가지고있다. 사용자는 "체크 아웃"항목을 사용하여 점수를 부여합니다. 한 번에 한 명의 사용자 만 항목을 체크 아웃 할 수 있습니다. 주어진 사용자에 대해 한 번에 20 개의 항목 블록을 요청해야합니다. 이러한 항목은 이미 체크 아웃 할 수 없으므로 사용자는 이전에 이미 점수를 매길 수 없습니다 (따라서 SELECT의 lock_field IS NULL 및 NOT EXISTS 문). item_ids 20 개 목록을 확인한 후에는 대기열 테이블을 업데이트하여 다른 사람이 동시에 체크 아웃 할 수 없도록 큐 테이블을 잠근 것으로 표시해야합니다. 또한 item_ids 목록을 반환해야합니다.

SQL Server 측에서 cftransaction에서 stored proc로 이동하면 더 잘 작동한다고 생각했습니다. cftransaction 잠금이 어떻게 든 방해가되는지 확실하지 않습니다. 나는 TSQL 전문가가 아니기 때문에 도움을 얻을 수있을 것이다.

+0

업데이트 작업을 보호하기 위해''이 있습니까? 이 방법으로 모든 동시성 문제는 없어집니다. – Tomalak

+0

업데이트가 cftransaction의 일부입니다. 나는 cflock이 필요하다고 확신하지 않습니다. –

+0

cftransaction은 오류가 발생하는 즉시 오류 내에서 실행 된 모든 SQL 문을 롤백합니다. 코드 섹션을 잠그지 않습니다. – Tomalak

답변

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; 
+0

빠른 답변 주셔서 감사합니다. 방금 깨달았지만, item_id가 아닌 select 쿼리에서 3 개의 필드를 모두 반환해야합니다. 어떻게 대답을 바꾸겠습니까? –

+0

OUTPUT inserted.item_id, inserted.field2, inserted.field3 –

+0

그래,이 코드를 새로운 저장된 proc에 놓을 수 있어야하고 분명히 # varname # ColdFusion 스타일 변수를 @varname proc 변수에 저장해야하고 모두 바꿔야한다. 좋아, 안 그래? –

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 

업데이트가 완료 될 때까지 선택한 항목이 잠겨 있는지 확인해야합니다.

편집 : 원본 질문과 마찬가지로 출력 절을 추가하여 어떤 행이 업데이트되었는지 알고 싶었습니다.

+0

네,하지만 SELECT 내부에 UPDATE를 넣는 문제는이 트랜잭션의 일부로 SELECT 쿼리의 내용을 반환해야한다는 것입니다. –

+0

왜 HOLDLOCK이 필요합니까? 업데이트를하고 있기 때문에 자물쇠가 열리지 않습니까? – erikkallen