c# transactionscope isolation-level

c# - ¿Por qué es System.Transactions TransactionScope predeterminado Isolationlevel Serializable



isolation-level (3)

Bueno, creo que este es uno de esos tipos de preguntas que "solo el diseñador sabría definitivamente". Pero aquí están mis dos centavos de todos modos:

Si bien Serializable es el nivel de aislamiento más "limitante" (en relación con el bloqueo, en un RDBMS basado en bloqueo y, por lo tanto, el acceso simultáneo, puntos muertos, etc.) también es el nivel de aislamiento más "seguro" (en lo que respecta a la coherencia de los datos).

Entonces, mientras se requiere trabajo adicional en escenarios como el tuyo (ya que he hecho eso ;-), tiene sentido optar por la variante más segura de forma predeterminada. SQL Server (T / SQL) elige usar READ COMMITTED , obviamente aplicando otras razones :-)

Hacerlo modificable por la configuración sería una mala idea, ya que al jugar con la configuración se podría convertir una aplicación que funciona perfectamente en una defectuosa (ya que podría no estar diseñada para funcionar con cualquier otra cosa). O para cambiar el argumento, al "codificar" el nivel de aislamiento, puede asegurarse de que su aplicación funciona como se espera. Podría decirse que el nivel de aislamiento no es un buen ajuste para una opción de configuración (mientras que el tiempo de espera de la transacción sí lo es).

Me pregunto cuál es una buena razón para usar Serializable como el nivel de aislamiento predeterminado cuando se crea el TransactionScope System.Transactions , porque no puedo pensar en ninguno (y parece que no puede cambiar el valor predeterminado a través de web/app.config por lo que Siempre hay que configurarlo en tu código).

using(var transaction = TransactionScope()) { ... //creates a Transaction with Serializable Level }

En su lugar, siempre tengo que escribir el código de repetición de esta manera:

var txOptions = new System.Transactions.TransactionOptions(); txOptions.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted; using(var transaction = new TransactionScope(TransactionScopeOption.Required,txOptions)) { ... // }

¿Algunas ideas?


El hecho de que Serializable es el valor predeterminado viene de los tiempos en que .NET ni siquiera se lanzó (antes del año 1999), de la programación de DTC ( Coordinador de transacciones distribuidas ).

DTC utiliza una enumeración ISOLATIONLEVEL nativa:

ISOLATIONLEVEL_SERIALIZABLE Los datos leídos por una transacción actual no pueden ser cambiados por otra transacción hasta que la transacción actual finalice. No se pueden insertar nuevos datos que afecten la transacción actual. Este es el nivel de aislamiento más seguro y es el predeterminado, pero permite el nivel más bajo de concurrencia.

.NET TransactionScope está construido sobre estas tecnologías.

Ahora, la siguiente pregunta es: ¿por qué DTC define ISOLATIONLEVEL_SERIALIZABLE como el nivel de transacción predeterminado? Supongo que es porque DTC fue diseñado alrededor del año 1995 (antes de 1999, sin duda). En ese momento, el estándar SQL era SQL-92 (o SQL2).

Y aquí está lo que dice SQL-92 sobre los niveles de transacción:

Una transacción SQL tiene un nivel de aislamiento que es LEER SIN COMPROMISO, LEER COMPROMETIDO, LEER REPETIBLE o SERIALIZABLE. El nivel de aislamiento de una transacción SQL define el grado en que las operaciones en datos SQL o esquemas en esa transacción SQL se ven afectadas por los efectos y pueden afectar operaciones en datos SQL o esquemas en transacciones SQL concurrentes. El nivel de aislamiento de una transacción SQL es SERIALIZABLE por defecto . El nivel se puede establecer explícitamente mediante la <set transaction statement> .

La ejecución de transacciones SQL concurrentes en el nivel de aislamiento SERIALIZABLE está garantizada para ser serializable. Una ejecución serializable se define como una ejecución de las operaciones de ejecución simultánea de transacciones SQL que produce el mismo efecto que algunas ejecuciones en serie de esas mismas transacciones SQL. Una ejecución en serie es aquella en la que cada transacción de SQL se ejecuta hasta su finalización antes de que comience la siguiente transacción de SQL.


Una forma útil de reducir el código de repetición de la escritura es envolverlo en una clase de constructor, de este modo:

public static class TransactionScopeBuilder { /// <summary> /// Creates a transactionscope with ReadCommitted Isolation, the same level as sql server /// </summary> /// <returns>A transaction scope</returns> public static TransactionScope CreateReadCommitted() { var options = new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted, Timeout = TransactionManager.DefaultTimeout }; return new TransactionScope(TransactionScopeOption.Required, options); } }

Entonces puede usarlo así al crear un alcance de transacción:

using (var scope = TransactionScopeBuilder.CreateReadCommitted()) { //do work here }

Puede agregar otros valores predeterminados de ámbito de transacción comunes a la clase de generador a medida que los necesite.