Lock de registro

22/07/2004 - 23:05 por Giovany | Informe spam
Un Saludo,como puedo realizar un bloqueo de un registro,
del tal manera que otros usuario no pueda leerlo mientras
la transaccion no haya terminado y actualizado dicho
registro, he probado con SET TRANSACTION ISOLATION LEVEL
SERIALIZABLE o poniendo la segerencia de bloque en el
from asi :

BEGIN TRANSACTION

SELECT numero+1
from correlativos WITH (XLOCK)
where aplicacion

Insert into pagos...

Update agenda_pagos
..

Update correlativos set numero=numero+1
where aplicacion

COMMIT TRANSACTION

pero la otra sesion tambien obtiene el mismo
numero, no se donde esta mi problema y seguramente no he
entendido bien forma de hacerlo,
si por favor pueden ayudarme.

le agradezco

Preguntas similare

Leer las respuestas

#1 Gustavo Larriera [MVP SQL]
23/07/2004 - 02:19 | Informe spam
No necesitas hacer nada especial ni cambiar el Isolation Level. El bloqueo
es automático y es la forma normal de funcionamiento.

BEGIN TRANSACTION
INSERT
UPDATE
UPDATE
COMMIT TRANSACTION


Gustavo Larriera
Uruguay LatAm
http://sqljunkies.com/weblog/gux/
Este mensaje se proporciona "COMO ESTA" sin garantias y no otorga ningun
derecho / This posting is provided "AS IS" with no warranties, and confers
no rights.
"Giovany" wrote in message
news:252701c4702f$9b5d8df0$
Un Saludo,como puedo realizar un bloqueo de un registro,
del tal manera que otros usuario no pueda leerlo mientras
la transaccion no haya terminado y actualizado dicho
registro, he probado con SET TRANSACTION ISOLATION LEVEL
SERIALIZABLE o poniendo la segerencia de bloque en el
from asi :

BEGIN TRANSACTION

SELECT numero+1
from correlativos WITH (XLOCK)
where aplicacion

Insert into pagos...

Update agenda_pagos
..

Update correlativos set numero=numero+1
where aplicacion

COMMIT TRANSACTION

pero la otra sesion tambien obtiene el mismo
numero, no se donde esta mi problema y seguramente no he
entendido bien forma de hacerlo,
si por favor pueden ayudarme.

le agradezco




Respuesta Responder a este mensaje
#2 SqlRanger [MVP .NET]
23/07/2004 - 10:08 | Informe spam
Lo primero deberías hacer es actualizar el correlativo a la vez que lo lees
para que se quede bloqueado de forma exclusiva durante toda la transacción.
Con un nivel de aislamiento de lectura confirmada sería suficiente:

BEGIN TRAN

declare @correlativo int
update correlativos
set @correlativo = numero = numero + 1
where aplicacion = 15

etc

COMMIT

Esto es equivalente a:


BEGIN TRAN

declare @correlativo int
update correlativos
set numero = numero + 1
where aplicacion = 15

select @correlativo = numero
from correlativos
where aplicacion = 15


COMMIT

Sin embargo lo primero es mejor (más eficiente) ya que todo se hace en una
única instrucción, en lugar de dos.



La técnica que estás usando no funciona correctamente porque la sugerencia
de bloqueo XLOCK no tiene efecto a no ser que especifiques además PAGLOCK o
TABLOCK. Sería así:

SELECT numero + 1
FROM Correlativos WITH(XLOCK, PAGLOCK)
WHERE Aplicacion = 15


De todas formas es preferible usar el primer método que te he sugerido ya
que así sólo se bloquea una fila en vez de una página entera.


Saludos:

Jesús
MVP
Respuesta Responder a este mensaje
#3 SqlRanger [MVP .NET]
23/07/2004 - 10:18 | Informe spam
Perdona que te contradiga Gustavo pero si lees un registro al comienzo de
una transacción con nivel de aislamiento de lectura confirmada, el bloqueo
compartido que SQL Server establece sobre la fila (o la clave del índice) al
leerlo, se libera inmediátamente después de haber sido leída la fila, no
manteniéndose dicho bloqueo durante el resto de la transacción. Lo cual no
impide que otra conexión pueda leer e incluso actualizar dicho registro
mientras se está ejecutando la transacción.

Con un nivel de aislamiento de lectura repetible, el bloqueo compartido
sobre la fila leída se mantiene durante toda la transacción, impidiendo que
otras conexiones modifiquen el registro mientras esté activa dicha
transacción, pero no impide que ese registro sea leído. Como otras
conexiones podrían estar ejecutando el mismo código al mismo tiempo, esto
daría lugar sin duda a interbloqueos, lo que no resulta nada deseable.

Con un nivel de aislamiento serializable, ocurriría algo similar que con
lectura repetible, a diferencia de que además estaría bloqueada la inserción
de registros que cumplieran la cláusula where de la instrucción select, para
evitar así la aparición de filas fantasma.

Saludos:

Jesús
MVP
Respuesta Responder a este mensaje
#4 Gustavo Larriera [MVP SQL]
23/07/2004 - 15:56 | Informe spam
El tema no es por las lecturas sino por las escrituras. Si una transaccion
T1 está leyendo y también escribiendo un dato, otra transacción T2 NO DEBE
leer el dato hasta que la primera transacción haya dado COMMIT. A menos que
se permitan operaciones de lecturas sucias (que para algunas pocas
aplicaciones se desea así, pero no es lo habitual en OLTP).

Probemos esto:

use tempdb
go
create table numero (idnumero int, numero min)
go
insert numero values (1, 0)


Veamos ahora esto. Abramos una Transacion1 en una ventana:

Transaccion1
begin transaction
select numero from numero
update numero set numero = numero + 1 where idnumero=1
commit transaction
Fin Transaccion1

En otra ventana abramos una Transaccion2:
Transaccion2
select numero from numero
Fin Transaccion2

La Transaccion2 (que solamente intenta leer) queda esperando hasta el COMMIT
de la Transaccion1. Cuando la T1 finaliza, recien entonces la T2 lee el
resultado correcto (numero ahora vale 1 en vez de 0).


Gustavo Larriera
Uruguay LatAm
http://sqljunkies.com/weblog/gux/
Este mensaje se proporciona "COMO ESTA" sin garantias y no otorga ningun
derecho / This posting is provided "AS IS" with no warranties, and confers
no rights.
"SqlRanger [MVP .NET]" wrote in message
news:
Perdona que te contradiga Gustavo pero si lees un registro al comienzo de
una transacción con nivel de aislamiento de lectura confirmada, el bloqueo
compartido que SQL Server establece sobre la fila (o la clave del índice)


al
leerlo, se libera inmediátamente después de haber sido leída la fila, no
manteniéndose dicho bloqueo durante el resto de la transacción. Lo cual no
impide que otra conexión pueda leer e incluso actualizar dicho registro
mientras se está ejecutando la transacción.

Con un nivel de aislamiento de lectura repetible, el bloqueo compartido
sobre la fila leída se mantiene durante toda la transacción, impidiendo


que
otras conexiones modifiquen el registro mientras esté activa dicha
transacción, pero no impide que ese registro sea leído. Como otras
conexiones podrían estar ejecutando el mismo código al mismo tiempo, esto
daría lugar sin duda a interbloqueos, lo que no resulta nada deseable.

Con un nivel de aislamiento serializable, ocurriría algo similar que con
lectura repetible, a diferencia de que además estaría bloqueada la


inserción
de registros que cumplieran la cláusula where de la instrucción select,


para
evitar así la aparición de filas fantasma.

Saludos:

Jesús
MVP


Respuesta Responder a este mensaje
#5 ulises
23/07/2004 - 17:10 | Informe spam
Pero Gustavo, eso no impide las lecturas, si tomamos tu
ejemplo de transacción, creamos unas tablas de prueba

create table contador (numero int )
create table tablamaestra ( numero int,
descripcion varchar(20) )
insert into contador values (0)

y luego creamos un procedimiento donde usamos WAITFOR para
simular la demora en un proceso :

create procedure insertaregistro ( @proceso varchar(20) )
as
declare @cont int
begin transaction
select @cont = numero from contador
set @cont = @cont + 1
waitfor delay '00:00:03'
insert tablamaestra values (@cont,@proceso)
update contador set numero = @cont
commit transaction

si ejecutas las siguientes sentencias en dos ventanas
diferentes :

insertaregistro 'proceso 01'
insertaregistro 'proceso 02'

obtenemos que la secuencia es la misma para ambos registros

numero descripcion
1 proceso 01
1 proceso 02

(2 row(s) affected)

la mejor manera de controlar la secuencia es leyendo y
actualizando el registro al mismo tiempo

Saludos,
Ulises

El tema no es por las lecturas sino por las escrituras.


Si una transaccion
T1 está leyendo y también escribiendo un dato, otra


transacción T2 NO DEBE
leer el dato hasta que la primera transacción haya dado


COMMIT. A menos que
se permitan operaciones de lecturas sucias (que para


algunas pocas
aplicaciones se desea así, pero no es lo habitual en


OLTP).

Probemos esto:

use tempdb
go
create table numero (idnumero int, numero min)
go
insert numero values (1, 0)


Veamos ahora esto. Abramos una Transacion1 en una ventana:

Transaccion1
begin transaction
select numero from numero
update numero set numero = numero + 1 where idnumero=1
commit transaction
Fin Transaccion1

En otra ventana abramos una Transaccion2:
Transaccion2
select numero from numero
Fin Transaccion2

La Transaccion2 (que solamente intenta leer) queda


esperando hasta el COMMIT
de la Transaccion1. Cuando la T1 finaliza, recien


entonces la T2 lee el
resultado correcto (numero ahora vale 1 en vez de 0).


Gustavo Larriera
Uruguay LatAm
http://sqljunkies.com/weblog/gux/
Este mensaje se proporciona "COMO ESTA" sin garantias y


no otorga ningun
derecho / This posting is provided "AS IS" with no


warranties, and confers
no rights.
"SqlRanger [MVP .NET]" wrote in


message
news:
Perdona que te contradiga Gustavo pero si lees un




registro al comienzo de
una transacción con nivel de aislamiento de lectura




confirmada, el bloqueo
compartido que SQL Server establece sobre la fila (o la




clave del índice)
al
leerlo, se libera inmediátamente después de haber sido




leída la fila, no
manteniéndose dicho bloqueo durante el resto de la




transacción. Lo cual no
impide que otra conexión pueda leer e incluso




actualizar dicho registro
mientras se está ejecutando la transacción.

Con un nivel de aislamiento de lectura repetible, el




bloqueo compartido
sobre la fila leída se mantiene durante toda la




transacción, impidiendo
que
otras conexiones modifiquen el registro mientras esté




activa dicha
transacción, pero no impide que ese registro sea leído.




Como otras
conexiones podrían estar ejecutando el mismo código al




mismo tiempo, esto
daría lugar sin duda a interbloqueos, lo que no resulta




nada deseable.

Con un nivel de aislamiento serializable, ocurriría




algo similar que con
lectura repetible, a diferencia de que además estaría




bloqueada la
inserción
de registros que cumplieran la cláusula where de la




instrucción select,
para
evitar así la aparición de filas fantasma.

Saludos:

Jesús
MVP






.

Respuesta Responder a este mensaje
Ads by Google
Help Hacer una preguntaSiguiente Respuesta Tengo una respuesta
Search Busqueda sugerida