2009-11-16 19 views
6

Estoy teniendo realmente problemas con una consulta en mi aplicación ColdFusion (retrocedido a MS SQL 2008). Quiero evitar errores de punto muerto DB en esta transacción:TSQL SELECT luego ACTUALIZAR en una transacción, luego devolver SELECCIONAR

<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, tengo una tabla (Tabla 1), que representa una gran cola de elementos de espera. Elementos de "pago y envío" de los usuarios para darles una puntuación. Solo un usuario puede tener un artículo desprotegido a la vez. Necesito solicitar un bloque de 20 elementos a la vez para un usuario dado. Esos elementos ya no pueden ser revisados ​​y el usuario ya no puede haberlos calificado previamente (de ahí que la instrucción lock_field IS NULL y NOT EXISTS en SELECT). Una vez que haya determinado la lista de 20 item_ids, necesito actualizar la tabla de cola para marcarlos como bloqueados para que nadie más los revise al mismo tiempo. También necesito devolver esa lista de item_ids.

Estaba pensando que podría funcionar mejor si moviera esto de una transacción de CF a un proceso almacenado en el lado de SQL Server. Simplemente no estoy seguro si el bloqueo de la transacción está interfiriendo de alguna manera. No soy un gurú de TSQL, por lo que sería de mucha ayuda.

+0

¿Tiene una '' cflock scope = "aplicación"> 'en su lugar para proteger su operación de ACTUALIZACIÓN? De esta forma, todos los problemas de concurrencia deberían desaparecer. – Tomalak

+0

La actualización es parte de la transacción cftransaction. No estoy seguro de que se necesite un cflock, ¿no? –

+0

Una transacción de CF simplemente retrotrae cada instrucción SQL emitida dentro de ella tan pronto como se produce un error. No bloquea esa sección de código. – Tomalak

Respuesta

12

Utilice una expresión de tabla común para seleccionar los datos, luego actualice el CTE y el resultado de la instrucción UPDATE. De esta manera todo es una operación:

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

Gracias por la respuesta rápida. Sin embargo, me di cuenta de que tengo que devolver los 3 campos de la consulta de selección, no solo el item_id. ¿Cómo cambiaría eso tu respuesta? –

+0

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

+0

Ok, entonces debería ser capaz de colocar este código en un nuevo proceso almacenado y, obviamente, cambiar los vars de estilo # varname # ColdFusion por @varname proc vars almacenados y todos deberían estar bien, no? –

2

no saber mucho (es decir: nada) sobre PHP, pero que tienen alguna experiencia con TSQL es posible que desee considerar la posibilidad de cambiar su consulta a algo como esto:

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 

Esto debería garantizar que los elementos que seleccione se bloquearán hasta que se complete la actualización.

editar: se agregó una cláusula de salida ya que la pregunta original también quería saber qué filas se actualizaron.

+0

Sí, pero el problema de colocar el elemento seleccionado dentro de la ACTUALIZACIÓN es que DEBO DEVOLVER el contenido de la consulta de selección como parte de esta transacción. –

+0

¿Por qué necesita HOLDLOCK? ¿No se realizará la cerradura de todos modos ya que estás haciendo una ACTUALIZACIÓN? – erikkallen

Cuestiones relacionadas