2009-12-17 20 views
7

que tienen un procedimiento como este:Thread transaction sql safe, cómo bloquear una fila específica durante una transacción?

create procedure Checkout 
@Foo nvarchar(20), 
@cost float 
as 
begin transaction 

declare @Bar nvarchar(20); 
select @Bar = Bar from oFoo where Foo = @Foo; 

update Foo set gold = gold - @cost where name = @Foo; 
update Bar set gold = gold + @cost where name = @Bar; 

delete from oFoo where @Foo = Foo; 

commit transaction 

necesito para bloquear la fila con Foo = @foo de la mesa oFoo durante esta operación para que nadie pudiera leer/editar/borrar, nadie sabe cómo hacerlo ?

estoy usando Microsoft SQL Server 2008

+0

creo que simplemente seleccionando una fila por lo general lo bloquea para el alcance de transacción a menos que haya reconfigurado el DB. ¿Trata eso? ¿Alguien mas? – martinr

+3

@martinr: SELECT colocará un bloqueo compartido, p. los datos aún se pueden modificar entre SELECT y la primera ACTUALIZACIÓN. – liggett78

+0

Necesita decirnos qué base de datos está utilizando, puede haber métodos específicos según la base de datos. –

Respuesta

8

Si quiere nadie para actualizar/borrar la fila, me gustaría ir con el UPDLOCK en la instrucción SELECT. Esto es una indicación de que actualizará la misma fila en breve, p.

select @Bar = Bar from oFoo WITH (UPDLOCK) where Foo = @Foo; 

Ahora bien, si desea que la situación en la que nadie debe ser capaz de leer el valor, así, que haría uso de la ROWLOCK (+ HOLDLOCK XLOCK para que sea exclusivo y para mantener hasta el final de la transacción).

Puede hacer TABLOCK (X), pero esto bloqueará toda la tabla para acceso exclusivo por esa transacción. Incluso si alguien viene y quiere ejecutar su procedimiento en una fila diferente (por ejemplo, con otro valor @Foo), se bloqueará hasta que se complete la transacción anterior.

Nota: se puede simular diferentes escenarios con este script:

CREATE TABLE ##temp (a int, b int) 
INSERT INTO ##temp VALUES (0, 0) 

cliente # 1

BEGIN TRAN 
SELECT * FROM ##temp WITH (HOLDLOCK XLOCK ROWLOCK) WHERE a = 0 
waitfor delay '0:00:05' 
update ##temp set a = 1 where a = 0 
select * from ##temp 
commit tran 

cliente # 2:

begin tran 
select * from ##temp where a = 0 or a = 1 
commit tran 
+0

+1 esta es la respuesta correcta –

+0

shoud tal vez ampliar que un updlock puede tener un bloqueo de página o un bloqueo de fila dependiendo de todo tipo de factores. –

1

Ver: http://www.mssqlcity.com/Articles/Adm/SQL70Locks.htm

Y: http://msdn.microsoft.com/en-us/library/ms173763.aspx

nota particularmente en la página de MSDN:

READ COMMITTED 

Specifies that statements cannot read data that has been modified but not committed 
by other transactions. This prevents dirty reads. Data can be changed by other 
transactions between individual statements within the current transaction, resulting 
in nonrepeatable reads or phantom data. This option is the SQL Server default. 
1

(Basado en SQL Server)

Creo que cuando se trata de consejos de mesa necesita experimentar (TABLOCK, TABLOCKX) y ver cuál se adapta mejor a usted. También tenga en cuenta que el optimizador de consultas puede ignorar las sugerencias. Las sugerencias a nivel de tabla se ignorarán si el optimizador de consultas no elige la tabla y la utiliza en el plan de consulta posterior.

Otro artículo útil sobre el tema, aunque un poco viejo como su en torno a SQL Server 2000 es SQL Server 2000 Table Locking Hints