Transascciones

20/10/2005 - 09:22 por solusoft | Informe spam
Hola a todos,

una pregunta, creoq ue se puede especificar el tipo de bloqueo en las
transacciones de .NET, pero c uál es el valor por defecto ?.

Estaba utilizando transascciones, y me bloquea la tabla para lectura y no
puedo insertar más de un registro por tabla.
Ya que tengo que insertar varios registros en una tabla y al hacer la
consulta del código para el siguiente registro (select max() + 1), me genera
un error.

Si no se puede, tengo que pensar en otra forma de hacerlo.
Pero tiene que haber una manera, porque no puede ser que bloquee toda la
tabla en modo lectura también, a no ser que sea una aplicación que requiera
ese nivel tan alto de protección. En la mayoría de los casos, lo lógico es
que bloquee solamente los registros afectados por la transaccion para
cualquier modificación o inserción.

Saludos cordiales.

Preguntas similare

Leer las respuestas

#11 Miguel Angel Campos
25/10/2005 - 08:38 | Informe spam
Muchas gracias por la respuesta.

Un Saludo,

Miguel Angel Campos
MCAD.NET

"Miguel Egea" escribió en el mensaje
news:
Me refiero a utilizar identitys por ejemplo, o utilizar select top 1 order
by ese campo desc y tener un índice descendente en ese campo, es decir
operaciones que ayuden al motor de base de datos a encontrar más
rápidamente el vlaor en cuestión y con menos sobrecarga.

Espero que ayude.

Saludos
Miguel Egea
"Miguel Angel Campos" <SPAMmacampos ARRUBA .idesarrollaSPAM.com> wrote in
message news:%
Hola Miguel,

¡muy buena explicación!, pero sólo me queda una duda con respecto al
método optimista que comentas al final, y es ¿qué? utilizar en lugar del
select max. Tengo claro que te refieres a un método de reintento mediante
detección de clave duplicada, pero me quedo ahí.
Un Saludo,

Miguel Angel Campos
MCAD.NET

"Miguel Egea" escribió en el mensaje
news:
Hola Octavio y amigos, un placer leerles,

El problema con lo que está haciendo nuestro amigo es que el select
max(x) +1 suele ser un gran generador de problemas, ya que nada impide a
dos o mas conexiones ejecutar el select max()+1 y encontrar el mismo
valor de clave al mismo tiempo, ni siquiera en el nivel serializable una
lectura impediría otra. lectura ya que lecturas no bloquean lecturas
(puedes usar hints para esto pero dudo mucho que tu aplicación quede muy
escalable).

Mi sugerencia para estas cosas es, create una tabla con el nombre de la
tabla y el valor del contador (si necesitas crear series añade la serie
como campo) algo así

Create table Claves (NombreTabla sysname not null primary key, contador
int) (si tu contador es un smallint o un bigint u otro tipo puedes hacer
una tabla para cada tipo diferente, esto no supone grandes problemas por
que no habrán muchas tablas)

Después create dos procedimientosAlmacenados uno puede ser el siguiente
(te lo escribo de memoria así que lo más normal es que no funcione, pero
será facil de corregir), observa que no le he puesto control de errores,
te lo dejo a que lo perfeccciones

Create Proc ObtenerId(@tabla sysname,@contador int output)
as
begin
begin tran
update Claves set @contador=contador=contador+1 where
NombreTabla=@Tabla
if @@rowcount=0 /* no existía el registro, hay que insentarlo)
begin
insert into Claves (NombreTabla, Contador) values (@tabla,1)
set @contador=1
end
commit tran
return 0
end

El otro procedimiento almacenado debería recibir un parámetro más que
sea cuantas claves quieres obtener por si necesitas hacer inserciones
masivas, no entro en detalles, igual si os hace falta puedo escribirlo y
publicarlo en PortalSQL.com

¿que beneficios obtienes con esto frente al select max?

Primero el update genera un bloqueo, ese bloqueo impide que dos
conexiones obtengan el mismo ID, es decir resultará beneficioso.
Segundo evitas un select max(), que dependiendo de tu indexacion y el
número de registros puede ser una tarea bastante costosa.
Tercero creas un método estandar para todas las tablas de obtener una
nueva clave primaria.

Hay más mecanismos, este es el "pesismista", en un mecanismo optimistas
puedes usar algo parecido al select max (no el select max en mi
opinión), y recuperarte del error por clave duplicada, quizá sea un poco
más escalable, pero hasta donde llega mi experiencia este método
funciona bastante bien y supone menor esfuerzo de programación.

Saludos
Miguel Egea
SQL Server MVP



"Octavio Hernandez" wrote in message
news:
Hola,

Por cierto, cómo puedo bloquear específicamente un registro de una
tabla y
no la tabla completa ?



Me parece recordar que la cláusula HOLDLOCK de SQL Server permite
lograr eso:


http://msdn.microsoft.com/library/d...z_4ox9.asp

Pruébalo, no estoy seguro de eso...

Slds - Octavio

"solusoft" escribió en el mensaje
news:
Gracias, el problema era que se utilizaba otra conexión para obtener
el
siguiente código (el select max() + 1) y claro, si había iniciado la
transacción con otra conexión, pues ahí estaban los problemas.


Por cierto, cómo puedo bloquear específicamente un registro de una
tabla y
no la tabla completa ?

Saludos


"Octavio Hernandez" escribió:

Hola,

El valor por defecto normalmente es ReadCommitted, como en el
proveedor de
SQL Server:


http://www.syncfusion.com/library/c...ltopic.htm

¿Puedes aportar el fragmento de código para ver exactamente qué estás
tratando de hacer?

Slds - Octavio

"solusoft" escribió en el
mensaje
news:
> Hola a todos,
>
> una pregunta, creoq ue se puede especificar el tipo de bloqueo en
> las
> transacciones de .NET, pero c uál es el valor por defecto ?.
>
> Estaba utilizando transascciones, y me bloquea la tabla para
> lectura y no
> puedo insertar más de un registro por tabla.
> Ya que tengo que insertar varios registros en una tabla y al hacer
> la
> consulta del código para el siguiente registro (select max() + 1),
> me
> genera
> un error.
>
> Si no se puede, tengo que pensar en otra forma de hacerlo.
> Pero tiene que haber una manera, porque no puede ser que bloquee
> toda la
> tabla en modo lectura también, a no ser que sea una aplicación que
> requiera
> ese nivel tan alto de protección. En la mayoría de los casos, lo
> lógico es
> que bloquee solamente los registros afectados por la transaccion
> para
> cualquier modificación o inserción.
>
> Saludos cordiales.
>
>
>
>
>





















Respuesta Responder a este mensaje
#12 solusoft
26/10/2005 - 13:15 | Informe spam
Gracias por su explicación, sería interesante para todos que apareciese en
PortalSQL.com.

Otra cuestión similar, y relacionada con los códigos (clave) es recuperar el
último código insertado, para los campos IDENTITY, pues puede plantearse algo
parecido, hacer un select max(), para recuperar el último código IDENTITY
insertado en la tabla, pero cómo sé yo exactamente que el código que recupero
es el realmente el insertado y no el de otro usuario.

Si utilizo una transacción para ejecutar select max() estaríamos en el mismo
caso de antes.

Muchísimas gracias, nos ayuda mucho.



"Miguel Egea" escribió:

Hola Octavio y amigos, un placer leerles,

El problema con lo que está haciendo nuestro amigo es que el select max(x)
+1 suele ser un gran generador de problemas, ya que nada impide a dos o mas
conexiones ejecutar el select max()+1 y encontrar el mismo valor de clave al
mismo tiempo, ni siquiera en el nivel serializable una lectura impediría
otra. lectura ya que lecturas no bloquean lecturas (puedes usar hints para
esto pero dudo mucho que tu aplicación quede muy escalable).

Mi sugerencia para estas cosas es, create una tabla con el nombre de la
tabla y el valor del contador (si necesitas crear series añade la serie como
campo) algo así

Create table Claves (NombreTabla sysname not null primary key, contador int)
(si tu contador es un smallint o un bigint u otro tipo puedes hacer una
tabla para cada tipo diferente, esto no supone grandes problemas por que no
habrán muchas tablas)

Después create dos procedimientosAlmacenados uno puede ser el siguiente (te
lo escribo de memoria así que lo más normal es que no funcione, pero será
facil de corregir), observa que no le he puesto control de errores, te lo
dejo a que lo perfeccciones

Create Proc ObtenerId(@tabla sysname,@contador int output)
as
begin
begin tran
update Claves set @contador=contador=contador+1 where NombreTabla=@Tabla
if @@rowcount=0 /* no existía el registro, hay que insentarlo)
begin
insert into Claves (NombreTabla, Contador) values (@tabla,1)
set @contador=1
end
commit tran
return 0
end

El otro procedimiento almacenado debería recibir un parámetro más que sea
cuantas claves quieres obtener por si necesitas hacer inserciones masivas,
no entro en detalles, igual si os hace falta puedo escribirlo y publicarlo
en PortalSQL.com

¿que beneficios obtienes con esto frente al select max?

Primero el update genera un bloqueo, ese bloqueo impide que dos conexiones
obtengan el mismo ID, es decir resultará beneficioso.
Segundo evitas un select max(), que dependiendo de tu indexacion y el número
de registros puede ser una tarea bastante costosa.
Tercero creas un método estandar para todas las tablas de obtener una nueva
clave primaria.

Hay más mecanismos, este es el "pesismista", en un mecanismo optimistas
puedes usar algo parecido al select max (no el select max en mi opinión), y
recuperarte del error por clave duplicada, quizá sea un poco más escalable,
pero hasta donde llega mi experiencia este método funciona bastante bien y
supone menor esfuerzo de programación.

Saludos
Miguel Egea
SQL Server MVP


Respuesta Responder a este mensaje
#13 Miguel Angel Campos
26/10/2005 - 17:13 | Informe spam
Ese caso es mas sencillo y está previsto en SQL Server mediante la función
SCOPE_IDENTITY(), devuelve el último valor de una columna identidad en la
sesión del usuario actual.

Un Saludo,

Miguel Angel Campos
MCAD.NET

"solusoft" escribió en el mensaje
news:
Gracias por su explicación, sería interesante para todos que apareciese en
PortalSQL.com.

Otra cuestión similar, y relacionada con los códigos (clave) es recuperar
el
último código insertado, para los campos IDENTITY, pues puede plantearse
algo
parecido, hacer un select max(), para recuperar el último código IDENTITY
insertado en la tabla, pero cómo sé yo exactamente que el código que
recupero
es el realmente el insertado y no el de otro usuario.

Si utilizo una transacción para ejecutar select max() estaríamos en el
mismo
caso de antes.

Muchísimas gracias, nos ayuda mucho.



"Miguel Egea" escribió:

Hola Octavio y amigos, un placer leerles,

El problema con lo que está haciendo nuestro amigo es que el select
max(x)
+1 suele ser un gran generador de problemas, ya que nada impide a dos o
mas
conexiones ejecutar el select max()+1 y encontrar el mismo valor de clave
al
mismo tiempo, ni siquiera en el nivel serializable una lectura impediría
otra. lectura ya que lecturas no bloquean lecturas (puedes usar hints
para
esto pero dudo mucho que tu aplicación quede muy escalable).

Mi sugerencia para estas cosas es, create una tabla con el nombre de la
tabla y el valor del contador (si necesitas crear series añade la serie
como
campo) algo así

Create table Claves (NombreTabla sysname not null primary key, contador
int)
(si tu contador es un smallint o un bigint u otro tipo puedes hacer una
tabla para cada tipo diferente, esto no supone grandes problemas por que
no
habrán muchas tablas)

Después create dos procedimientosAlmacenados uno puede ser el siguiente
(te
lo escribo de memoria así que lo más normal es que no funcione, pero será
facil de corregir), observa que no le he puesto control de errores, te lo
dejo a que lo perfeccciones

Create Proc ObtenerId(@tabla sysname,@contador int output)
as
begin
begin tran
update Claves set @contador=contador=contador+1 where
NombreTabla=@Tabla
if @@rowcount=0 /* no existía el registro, hay que insentarlo)
begin
insert into Claves (NombreTabla, Contador) values (@tabla,1)
set @contador=1
end
commit tran
return 0
end

El otro procedimiento almacenado debería recibir un parámetro más que sea
cuantas claves quieres obtener por si necesitas hacer inserciones
masivas,
no entro en detalles, igual si os hace falta puedo escribirlo y
publicarlo
en PortalSQL.com

¿que beneficios obtienes con esto frente al select max?

Primero el update genera un bloqueo, ese bloqueo impide que dos
conexiones
obtengan el mismo ID, es decir resultará beneficioso.
Segundo evitas un select max(), que dependiendo de tu indexacion y el
número
de registros puede ser una tarea bastante costosa.
Tercero creas un método estandar para todas las tablas de obtener una
nueva
clave primaria.

Hay más mecanismos, este es el "pesismista", en un mecanismo optimistas
puedes usar algo parecido al select max (no el select max en mi opinión),
y
recuperarte del error por clave duplicada, quizá sea un poco más
escalable,
pero hasta donde llega mi experiencia este método funciona bastante bien
y
supone menor esfuerzo de programación.

Saludos
Miguel Egea
SQL Server MVP





Respuesta Responder a este mensaje
#14 Miguel Egea
30/10/2005 - 21:09 | Informe spam
Así es, SQL tiene tres funciones para obtener el identity
SCOPE_Identity() devuelve ese valor en el alcance actual, es decir si un
trigger inserta en otra tabla con identity no tendría problemas.
@@identity devuelve el último identity insertado, es decir con ese
hipotético trigger si tendria problemas
e Ident_current() que devuelve el último valor de identidad insertado en una
tabla (se a o no de mi sesión).

Lo pondré en portalsql, gracias por la sugerencia.


Miguel Egea
Visita mi web http://www.portalsql.com
SQL Server MVP, Mentor
Solid Quality Learning
http://www.SolidQualityLearning.com
"Solid Quality Learning is the trusted global provider of advanced education
and solutions for the entire Microsoft database platform"

"Miguel Angel Campos" <SPAMmacampos ARRUBA .idesarrollaSPAM.com> wrote in
message news:%23d55K$
Ese caso es mas sencillo y está previsto en SQL Server mediante la función
SCOPE_IDENTITY(), devuelve el último valor de una columna identidad en la
sesión del usuario actual.

Un Saludo,

Miguel Angel Campos
MCAD.NET

"solusoft" escribió en el mensaje
news:
Gracias por su explicación, sería interesante para todos que apareciese
en
PortalSQL.com.

Otra cuestión similar, y relacionada con los códigos (clave) es recuperar
el
último código insertado, para los campos IDENTITY, pues puede plantearse
algo
parecido, hacer un select max(), para recuperar el último código IDENTITY
insertado en la tabla, pero cómo sé yo exactamente que el código que
recupero
es el realmente el insertado y no el de otro usuario.

Si utilizo una transacción para ejecutar select max() estaríamos en el
mismo
caso de antes.

Muchísimas gracias, nos ayuda mucho.



"Miguel Egea" escribió:

Hola Octavio y amigos, un placer leerles,

El problema con lo que está haciendo nuestro amigo es que el select
max(x)
+1 suele ser un gran generador de problemas, ya que nada impide a dos o
mas
conexiones ejecutar el select max()+1 y encontrar el mismo valor de
clave al
mismo tiempo, ni siquiera en el nivel serializable una lectura impediría
otra. lectura ya que lecturas no bloquean lecturas (puedes usar hints
para
esto pero dudo mucho que tu aplicación quede muy escalable).

Mi sugerencia para estas cosas es, create una tabla con el nombre de la
tabla y el valor del contador (si necesitas crear series añade la serie
como
campo) algo así

Create table Claves (NombreTabla sysname not null primary key, contador
int)
(si tu contador es un smallint o un bigint u otro tipo puedes hacer una
tabla para cada tipo diferente, esto no supone grandes problemas por que
no
habrán muchas tablas)

Después create dos procedimientosAlmacenados uno puede ser el siguiente
(te
lo escribo de memoria así que lo más normal es que no funcione, pero
será
facil de corregir), observa que no le he puesto control de errores, te
lo
dejo a que lo perfeccciones

Create Proc ObtenerId(@tabla sysname,@contador int output)
as
begin
begin tran
update Claves set @contador=contador=contador+1 where
NombreTabla=@Tabla
if @@rowcount=0 /* no existía el registro, hay que insentarlo)
begin
insert into Claves (NombreTabla, Contador) values (@tabla,1)
set @contador=1
end
commit tran
return 0
end

El otro procedimiento almacenado debería recibir un parámetro más que
sea
cuantas claves quieres obtener por si necesitas hacer inserciones
masivas,
no entro en detalles, igual si os hace falta puedo escribirlo y
publicarlo
en PortalSQL.com

¿que beneficios obtienes con esto frente al select max?

Primero el update genera un bloqueo, ese bloqueo impide que dos
conexiones
obtengan el mismo ID, es decir resultará beneficioso.
Segundo evitas un select max(), que dependiendo de tu indexacion y el
número
de registros puede ser una tarea bastante costosa.
Tercero creas un método estandar para todas las tablas de obtener una
nueva
clave primaria.

Hay más mecanismos, este es el "pesismista", en un mecanismo optimistas
puedes usar algo parecido al select max (no el select max en mi
opinión), y
recuperarte del error por clave duplicada, quizá sea un poco más
escalable,
pero hasta donde llega mi experiencia este método funciona bastante bien
y
supone menor esfuerzo de programación.

Saludos
Miguel Egea
SQL Server MVP









email Siga el debate Respuesta Responder a este mensaje
Ads by Google
Help Hacer una pregunta AnteriorRespuesta Tengo una respuesta
Search Busqueda sugerida