Es un novato en el trabajo de DB, así que aprecia tu paciencia con una pregunta básica. Estoy ejecutando SQL Server 2014 en mi máquina local, y tengo una pequeña tabla y una aplicación cliente básica para probar diferentes enfoques. Me estoy poniendo lo que parece ser un bloqueo de tabla durante tanto INSERT INTO
y UPDATE
declaraciones. El cliente es una aplicación ASP.NET con el siguiente código:
OleDbConnection cn = new OleDbConnection("Provider=SQLNCLI11; server=localhost\\SQLEXPRESS; Database=<my db>; user id=<my uid>; password=<my pwd>");
cn.Open();
OleDbTransaction tn = cn.BeginTransaction();
OleDbCommand cmd = new OleDbCommand("INSERT INTO LAYOUTSv2 (LAYOUTS_name_t, LAYOUTS_enabled_b, LAYOUTS_data_m) VALUES ('name', '-1', 'data')", cn, tn);
cmd.ExecuteNonQuery();
cmd.CommandText = "SELECT SCOPE_IDENTITY()";
int newkey = Decimal.ToInt32((decimal)cmd.ExecuteScalar());
Console.WriteLine("Created index " + newkey);
Thread.Sleep(15000);
tn.Commit();
tn = cn.BeginTransaction();
cmd.CommandText = "UDPATE LAYOUTSv2 SET LAYOUTS_enabled_b='-3' WHERE LAYOUTS_key='" + newkey + "'";
cmd.Transaction = tn;
cmd.ExecuteNonQuery();
Console.WriteLine("updated row");
Thread.Sleep(15000);
tn.Rollback();
cn.Close();
Ejecuto este código, luego desde el estudio de administración que ejecuto SELECT * FROM LAYOUTSv2
. Durante ambos casos, cuando el hilo del cliente está en pausa (es decir, antes de la confirmación / reversión), la consulta SELECT se bloquea hasta que se produce la confirmación / reversión.
La tabla tiene el campo LAYOUTS_key asignado como clave principal. En la ventana de propiedades muestra que es único y está agrupado, con bloqueos de página y bloqueos de fila permitidos. La configuración de escalado de bloqueo para la tabla es Desactivar ... He probado las otras configuraciones disponibles de Tabla y AUTO sin cambios. Lo intenté SELECT ... WITH (NOLOCK)
y eso arroja un resultado de inmediato, pero como está bien advertido aquí y en otros lugares, no es lo que debería estar haciendo. He intentado poner la ROWLOCK
pista en las declaraciones INSERT
y UPDATE
, pero nada ha cambiado.
El comportamiento que estoy buscando es el siguiente: antes de confirmar un INSERT
, las consultas de otros subprocesos leen todas las filas, excepto la que se está INSERT
editando. Antes de confirmar una UPDATE
consulta de otros hilos, lea la versión inicial de la fila que se está UPDATE
editando. ¿Hay alguna manera de que pueda hacer esto? Si necesito proporcionar otra información para aclarar mi caso de uso, hágamelo saber. Gracias.
fuente
WHERE LAYOUTS_key='" + newkey + "'
es un no-no completo por varias razones, incluida la inyección de SQL, debe usar consultas parametrizadas.newkey
"something';DELETE FROM LAYOUTSv2 --
". Su actualización se completará con éxito y luego vaciará la tabla porque el usuario manipuló la consulta insertando un apóstrofe. Normalmente, una consulta parametrizada se parece a algo asíUDPATE LAYOUTSv2 SET LAYOUTS_enabled_b='-3' WHERE LAYOUTS_key=?
, después de lo cual asigna valores por separado al?
(parámetro) en su código.Respuestas:
Lo más probable es que no esté bloqueando la "mesa completa".
Está bloqueando una fila en la tabla, pero
SELECT * FROM LAYOUTSv2
intenta leer toda la tabla, por lo que necesariamente está bloqueado por ese bloqueo.Para el caso de inserción, simplemente puede especificar la
READPAST
pista para saltar más allá de la fila bloqueada; sin embargo, eso no dará el resultado deseado para elUPDATE
caso (saltará la fila nuevamente y no leerá la versión inicial de la fila).Si configura la base de datos para el aislamiento de instantáneas confirmadas por lectura, esto le dará el efecto deseado para ambos casos (a expensas de un mayor uso de
tempdb
)fuente
SNAPSHOT
aislamiento mejor para dejarlo deshabilitado y luego habilitarlo si posteriormente decide que esto sería útil para usted.Se supone que las instrucciones de inserción y actualización crean bloqueos a nivel de fila. Sin embargo, cuando el número de bloqueos en cualquier transacción es de 5,000 o más, se produce una escalada de bloqueo y se crea un bloqueo a nivel de tabla. Por favor ver más abajo.
https://technet.microsoft.com/en-us/library/ms184286(v=sql.105).aspx
fuente