Gestión de transacciones en SQL Server

Sergio Alcalde | 17 de diciembre de 2008 | Añadir comentario

Más sobre: Documentación, SQL Server | Tags: , , ,

Conocer la gestión de transacciones que realiza SQL Server, qué son y cómo funcionan, es la clave para desarrollar aplicaciones eficaces y eficientes que se conectan a un gestor de bases de datos (SGBD) para consultar y modificar datos, con usuarios accediendo concurrentemente para realizar acciones de distinta naturaleza sobre los mismos (no es lo mismo consultar información que actualizarla) y teniendo que gestionar acciones de actualización que afectan a varios datos a la vez.

Este es el primero de una serie de posts en los que voy a explicar todo lo que hay que saber para gestionar este tipo de problemas.

Procesamiento de transacciones

Una transacción es una unidad lógica de trabajo que tiene ciertas propiedades conocidas como propiedades ACID: atomicidad, coherencia, aislamiento y permanencia.

Es responsabilidad del sistema gestor de bases de datos el asegurar que se cumplan estas propiedades. Sin embargo, el programador dispone de un cierto grado de control sobre la forma en que SQL Server gestiona algunas de estas propiedades.

Existen tres formas de llevar a cabo este procesamiento: autoconfirmación, explícita e implícita (que no voy a abordar en este post pero que os animo a comentar si lo creéis interesante).

Transacciones y bloqueos

SQL Server realiza y mantiene una serie de bloqueos durante la transacción. Existen dos formas de modificar el tratamiento de los bloqueos.

La primera de ellas consiste en introducir cláusulas en las sentencias “select”. Estas cláusulas modificarán el tratamiento de los bloqueos de las unidades afectadas (filas, tablas, páginas; la granularidad también es seleccionable y se tratará más adelante) por la sentencia y se mantendrán hasta la finalización de la transacción.

La segunda, se mantiene durante toda la sesión. Para modificar la forma en que una sentencia “select” gestiona una transacción y sus bloqueos se utiliza la sentencia “set transaction isolation level” que tiene las siguientes opciones o niveles de aislamiento, mutuamente excluyentes:

  • “read committed”: Es el comportamiento predeterminado. La transacción mantiene bloqueos compartidos durante el tiempo que dure la lectura. La transacción puede encontrarse con lecturas no repetibles o datos fantasma dado que el bloqueo no impide a otras transacciones modificar los datos que se han leído.
  • “read uncommitted”: Con este nivel de aislamiento una transacción puede leer datos sucios de otras transacciones. Es el nivel de aislamiento menos restrictivo. Esta opción tiene el mismo efecto que usar la opción “nolock” en una sentencia “select”.
  • “repeatable read”: A medida que se leen datos se establecen bloqueos de forma que otra transacción no pueda modificar datos leídos. Este nivel de aislamiento es más restrictivo y puede hacer que otras transacciones se bloqueen. No evita que se puedan añadir nuevas filas.
  • “snapshot”: Con este nivel de aislamiento las consultas de la transacción en curso sólo leerán los datos confirmados antes del comienzo de la misma. Dado que la transacción en curso trabaja con una instantánea de los datos, capturada en el momento de inicio de la transacción, las lecturas de datos de esta transacción no solicitan bloqueos y otras transacciones que realicen operaciones de escritura no bloquearán a ésta.
  • “serializable”: Nivel de aislamiento más restrictivo ya que aplica un bloqueo al rango de datos leídos. Proporciona, por tanto, protección ante lectura de filas fantasma.

Supervisión de transacciones

La supervisión de transacciones se apoya en el registro de transacciones. Para llevar la cuenta del número de transacciones abiertas, SQL Server utiliza una variable global de sesión denominada “@@trancount”.

Codificación de transacciones eficientes

Las transacciones tienen un efecto negativo en la concurrencia de acceso a datos. Para reducir la contienda de bloqueo sobre los recursos, las transacciones deben ser tan cortas y eficientes como sea posible. A continuación se enumeran algunas reglas que se deben observar al programar transacciones:

  • No devolver conjuntos de resultados dentro de una transacción. Dicha acción prolonga la transacción innecesariamente. Se debe realizar la recuperación y análisis de los datos fuera de la transacción.
  • Se debe evitar, en la medida de lo posible, pedir al usuario una respuesta cuando se haya iniciado una transacción. En caso de error se debe cerrar primero la transacción y después mostrar el mensaje de error.
  • La transacción debe ser lo más corta posible. Se debe abrir justo en el momento en el que se deseen realizar las modificaciones y cerrarla justo después de haberlas realizado.
  • Iniciar y terminar transacciones es un proceso que necesita una gran cantidad de trabajo por parte del servidor, por ello se deben abrir transacciones únicamente cuando sea necesario.

Conexiones acopladas

Como se ha comentado anteriormente, las transacciones tienen un efecto negativo en la concurrencia al acceso de datos.

Si es necesario implementar una transacción de larga duración manteniendo, por tanto, bloqueos exclusivos, y que continúe siendo posible algún tipo de procesamiento operativo, las conexiones acopladas o enlazadas pueden ser una solución. Existen dos tipos de conexiones acopladas: locales y distribuidas:

Las conexiones acopladas locales son conexiones dentro de un único servidor que comparten un espacio de transacciones.

Las conexiones acopladas distribuidas hacen uso del coordinador de transacciones distribuidas para que se comparta el mismo espacio de transacciones entre conexiones procedentes de más de un servidor.

Las conexiones enlazadas son útiles al desarrollar procedimientos almacenados extendidos que deben ejecutar instrucciones de Transact-SQL en nombre del proceso que las llama. Pasar el proceso que realiza la llamada en un testigo enlazado como un parámetro del procedimiento almacenado extendido permite al procedimiento combinar el espacio de transacciones del proceso que realiza la llamada y, por ello, integrar el procedimiento almacenado extendido con el proceso que realiza la llamada.

Se puede utilizar conexiones enlazadas para desarrollar aplicaciones en tres estratos en las que la lógica comercial se representa en programas independientes que funcionan en colaboración en una sola transacción comercial.

El ejemplo siguiente de conexiones enlazadas ilustra cómo pueden tener acceso dos conexiones a la misma transacción: Un cliente decide adquirir un producto a unos grandes almacenes locales. El vendedor obtiene acceso al sistema de transacciones de ventas que inserta una fila en la tabla de transacciones de ventas e incluye un número de autorización de tarjeta de crédito. Se realizan dos conexiones con el mismo servidor, la conexión C1 y la conexión C2. C1 comienza una transacción que agrega una fila de venta de productos a la tabla de ventas. Se debe agregar un número de autorización de tarjeta de crédito a la nueva fila de transacciones de ventas. Durante el proceso de autorización de la tarjeta de crédito, el procedimiento almacenado extendido crea la conexión C2 para conectar mediante la línea telefónica con la compañía de tarjetas de crédito y modifica la fila de transacciones de ventas con el número de autorización de la tarjeta de crédito. Solamente mediante la utilización de conexiones enlazadas, ambas conexiones pueden tener acceso a la misma fila sin que se produzcan conflictos de bloqueo.

Existe una importante desventaja de las transacciones acopladas: el procesamiento secuenciado. Sólo una de entre todas las conexiones acopladas puede estar realizando una operación. Cualquier intento de efectuar una tarea mientras que la anterior operación está teniendo lugar dará como resultado un error, que debe detectarse para su posterior tratamiento.

Transacciones distribuidas

Dada la creciente utilización de los sistemas distribuidos, existe la necesidad de acceder y modificar datos distribuidos.

Es necesaria una forma de asegurar que la transacción distribuida opere de la misma forma que lo haría una transacción local y que respete las propiedades ACID de cualquier transacción.

SQL Server proporciona las sentencias “begin distributed transaction” para comenzar una transacción distribuida.

El manejo de estas transacciones se realiza mediante el protocolo de confirmación en dos fases.

Leer más sobre:

  1. Gestión de transacciones en SQL Server (1/7)
  2. Gestión de bloqueos en SQL Server (2/7)
  3. Enfoques de control de transacciones en SQL Server (3/7)
  4. Enfoque optimista de gestión de transacciones en SQL Server (4/7)
  5. Enfoque pesimista de gestión de transacciones en SQL Server (5/7)
  6. Enfoque mixto de gestión de transacciones en SQL Server (6/7)
  7. Interbloqueos en SQL Server (7/7)

Más sobre: Documentación, SQL Server | Tags: , , ,