web-dev-qa-db-fra.com

Pourquoi System.Transactions TransactionScope par défaut Isolationlevel Serializable

Je me demande simplement quelle bonne raison d'utiliser Serializable comme niveau d'isolation par défaut peut être lors de la création d'un System.Transactions TransactionScope , car je ne peux penser à aucun (et il semble que vous ne pouvez pas changer la valeur par défaut via web/app.config donc vous devez toujours le définir dans votre code)

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

Au lieu de cela, je dois toujours écrire du code passe-partout comme ceci:

var txOptions = new System.Transactions.TransactionOptions();
txOptions.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted;

using(var transaction = new TransactionScope(TransactionScopeOption.Required, txOptions)) 
{
    ...
}

Des idées?

67
Bernhard Kircher

Le fait que Serializable est la valeur par défaut vient de l'époque où .NET n'était même pas sorti (avant l'année 1999), de la programmation DTC ( Distributed Transaction Coordinator ).

DTC utilise une énumération native ISOLATIONLEVEL :

ISOLATIONLEVEL_SERIALIZABLE Les données lues par une transaction en cours ne peuvent pas être modifiées par une autre transaction tant que la transaction en cours n'est pas terminée. Aucune nouvelle donnée ne peut être insérée qui pourrait affecter la transaction en cours. Il s'agit du niveau d'isolement le plus sûr et par défaut, mais autorise le niveau de concurrence le plus bas.

.NET TransactionScope est basé sur ces technologies.

Maintenant, la question suivante est: pourquoi DTC définit ISOLATIONLEVEL_SERIALIZABLE comme niveau de transaction par défaut? Je suppose que c'est parce que le DTC a été conçu vers 1995 (avant 1999 bien sûr). À cette époque, la norme SQL était SQL-92 (ou SQL2).

Et voici ce que SQL-92 dit à propos des niveaux de transaction:

Une transaction SQL a un niveau d'isolement qui est LECTURE NON ENGAGÉE, LECTURE COMMISE, LECTURE RÉPÉTABLE ou SÉRIALISABLE. Le niveau d'isolement d'une transaction SQL définit le degré auquel les opérations sur les données SQL ou les schémas de cette transaction SQL sont affectées par les effets de et peuvent affecter les opérations sur les données SQL ou les schémas dans des transactions SQL simultanées. Le niveau d'isolement d'une transaction SQL est SERIALIZABLE par défaut . Le niveau peut être explicitement défini par le <set transaction statement>.

L'exécution de transactions SQL simultanées au niveau d'isolement SERIALIZABLE est garantie d'être sérialisable. Une exécution sérialisable est définie comme une exécution des opérations d'exécution simultanée de transactions SQL qui produit le même effet qu'une exécution en série de ces mêmes transactions SQL. Une exécution en série est une exécution dans laquelle chaque transaction SQL s'exécute jusqu'à son terme avant le début de la prochaine transaction SQL.

82
Simon Mourier

Un moyen utile de réduire l'écriture de code passe-partout est de l'envelopper dans une classe de générateur comme ceci:

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);
    } 
}

Ensuite, vous pouvez l'utiliser comme ceci lors de la création d'une étendue de transaction:

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

Vous pouvez ajouter d'autres valeurs par défaut communes d'étendue de transaction à la classe de générateur selon vos besoins.

46
Almond

Eh bien, je suppose que c'est l'une de ces questions "seul le concepteur saurait certainement". Mais voici mes deux cents de toute façon:

Si Serializable est le niveau d'isolement le plus "limitant" (concernant le verrouillage, dans un SGBDR basé sur un verrou, et donc l'accès simultané, les blocages, etc.), il est également le niveau d'isolement le plus "sûr" (concernant la cohérence des données).

Ainsi, tout en nécessitant un travail supplémentaire dans des scénarios comme le vôtre (il y a eu cela ;-), il est logique d'opter par défaut pour la variante la plus sûre. SQL Server (T/SQL) choisit d'utiliser READ COMMITTED , en appliquant évidemment d'autres raisons :-)

La rendre modifiable par la configuration serait alors une mauvaise idée, car en jouant avec la configuration, vous pourriez rendre une application fonctionnant parfaitement en une application cassée (car elle pourrait tout simplement ne pas être conçue pour fonctionner avec autre chose). Ou pour inverser l'argument, en "codant en dur" le niveau d'isolement, vous pouvez vous assurer que votre application fonctionne comme prévu. On peut dire que le niveau d'isolement ne convient pas à une option de configuration (alors que délai d'expiration de la transaction l'est effectivement).

27
Christian.K