IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Accès aux données Discussion :

Database et Multithreads


Sujet :

Accès aux données

  1. #1
    Membre confirmé
    Inscrit en
    Mai 2008
    Messages
    125
    Détails du profil
    Informations personnelles :
    Âge : 42

    Informations forums :
    Inscription : Mai 2008
    Messages : 125
    Par défaut Database et Multithreads
    bonjour à tous,

    Je souhaiterais développer une application qui extrait des emails depuis Exchange et les insère les informations dans une base de données, mais avant de me lancer, je souhaiterais eclaircir quelques points...

    pouvez vous m'aider ou me conseiller quand à la façon de développer l'application, sachant qu'il y aura un client windows (console d'administration), et un service WCF (service d'extraction des emails).

    La ou je bloque un peu, c'est sur la gestion des connexions SQL. Sachant que je souhaite utiliser postgreSQL, je ne sais pas trop si je dois ouvrir une connexion pour chaque thread, ou utiliser une connexion pour l'ensemble des threads, sachant que je souhaite utiliser les transactions (TransactionScope)....

    De plus, j'ai regardé un peu la doc de postgreSQL et j'ai un peu de mal avec les paramètres "max_connexions" et "max_prepared_transactions"...

    Encore merci pour vos conseils.

  2. #2
    Expert confirmé
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 197
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 197
    Billets dans le blog
    1
    Par défaut
    Sans plus d'informations (et ça tombe bien, on frise la limite de mes connaissances ) je dirais les généralités suivantes :
    - .NET et son GC font automatiquement du pooling et de la réutilisation de connexions
    - La plupart du temps, les connecteurs de base de données supportent aussi des mécanismes automatisés de pooling (vérifier avec PostgreSQL, mais je suis presque certain que c'est le cas)

    Ainsi :
    - Lorsqu'une méthode de n'importe quel thread Close() une connexion (même explicitement) et libère la ressource Dispose() (même explicitement) la connexion est récupérée par le GC et remise en pool sans forcément être fermée ni terminée.
    - Lorsqu'une méthode de n'importe quel thread Open() une connexion, si elle comporte la même chaîne de connexion qu'une connection en pool (même base, même utilisateur, même paramètres) alors celle du pool est réutilisée.

    Par conséquent :
    - Multithread ou non, il faut systématiquement utiliser using() sur tous les objets de bdd (connexion, transaction, command notamment)
    - Il faut systématiquement Open() et Close() immédiatement avant et après utilisation (bon, évidement, si t'as 4 requêtes à faire à la suite, tu fermes pas la connexion entre les requêtes...)
    - Lors de l'ouverture d'une nouvelle connexion, le CG peut décider de réutiliser une autre connexion déjà ouverte et en cours d'utilisation par un autre thread. Il cloisonne alors les deux traitements dans des transactions séparées.

    Au niveau des transactions, il faut savoir :
    - Que lorsque tu fais un Close() (même si la connexion reste ouverte et remise en pool) un Rollback est fait sur toutes les transaction en cours
    - Qu'une transaction ouverte peut potentiellement générer les LOCKS dans la base, d'où l'intéret de conserver les objets ouverts le moins longtemps possible

    Après, on a parfois besoin de gérer des locks "manuellement", et là on est obligé de conserver des connexions et transactions ouvertes pendant longtemps. Mais ça doit se faire sciemment, et à bon escient.
    Exemple : http://www.developpez.net/forums/d11...rrous-rowlock/

  3. #3
    Membre confirmé
    Inscrit en
    Mai 2008
    Messages
    125
    Détails du profil
    Informations personnelles :
    Âge : 42

    Informations forums :
    Inscription : Mai 2008
    Messages : 125
    Par défaut
    Merci StringBuilder; ça commence à devenir un peu plus claire dans ma tête...

    J'ai commencé un peu cet après midi, et comme ut le mentionnes

    Que lorsque tu fais un Close() (même si la connexion reste ouverte et remise en pool) un Rollback est fait sur toutes les transaction en cours
    J'utilise bien le using avec TransactionScope, puis le Complete une fois la transaction terminée (ou le close en cas de problème et donc, le rollback). J'ai rajouté le Dispose, même si c'est explicite.

    Par contre, j'ai pas pensé à utiliser le using pour les commandes (et j'en ai pas mal d'ailleurs.... Est-ce que tu as un exemple d'utilisation de plusieurs commandes avec un using s'il te plait ?

    Je suis en train de me renseigner sur la façon dont PostgreSQL fonctionne et sur ses paramètres de connexions et de pooling (c'est possible avec PostgreSQL, mais désactivé par défaut avec le paramètre max_prepared_transactions qui est à 0, si j'ai bien tout compris )...

    Encore merci pour ton aide !

  4. #4
    Expert confirmé
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 197
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 197
    Billets dans le blog
    1
    Par défaut
    Bah le using sur un command n'est pas compliqué, je ne vois pas trop la question :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    using (SqlCommand cmd = cnx.CreateCommand())
    {
        [...]
    }
    Et quand tu as besoin de faire plusieurs requêtes à la suite, utilise au maximum le même command.
    N'oublie pas de faire un cmd.Parameters.Clear() à chaque fois pour vider les paramètres (à moins qu'ils ne soient identiques d'une requête à l'autre).

    Par contre, tu parles de TransactionScope, et ça, je n'ai aucune idée de ce que c'est, donc je peux pas du tout te conseiller là dessus...

  5. #5
    Expert confirmé
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 197
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 197
    Billets dans le blog
    1
    Par défaut
    Après avoir regardé rapidement la doc de C#, j'ai compris ce qu'était le transaction scope.

    As-tu vraiment besoin de cette fonctionnalité ?

    Il s'agit de transactions en dehors du SGBD. Cela implique donc que :
    - Ca crée une transaction dans le SGBD
    - MAIS AUSSI dans ton programme. C'est à dire que si tu annules la transaction tu rollback dans la base, mais aussi tout ce que ton programme à fait (modification de variables, de fichiers,etc.) Ca me semble un peu lourd si ce n'est pas pour gérer des cas très précis.

    Je pense que tu dois pouvoir te contenter des transactions du SGBD, à savoir l'objet SqlTransaction (ou PgTransaction, je ne sais pas comment sont préfixées les classes pour Posgresql)

  6. #6
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Février 2003
    Messages
    2 196
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2003
    Messages : 2 196
    Par défaut
    Il s'agit de transactions en dehors du SGBD. Cela implique donc que :
    - Ca crée une transaction dans le SGBD
    - MAIS AUSSI dans ton programme. C'est à dire que si tu annules la transaction tu rollback dans la base, mais aussi tout ce que ton programme à fait (modification de variables, de fichiers,etc.) Ca me semble un peu lourd si ce n'est pas pour gérer des cas très précis.
    Euh je pense pas, pour moi l'avantage du TransactionScoope c'est que tu peux imbriquer des transactions

    Exemple tu as une Methode1 qui fait appelle à une transaction et une Méthode2 qui fait appelle aussi a une transaction
    Après tu as une Methode3 qui commence une transaction et qui appelle Methode1 et Methode2 et qui commit la transaction

    Sans transaction scope la Methode 1 et 2 auraient toute deux sauvés les modifications alors que Methode3 fait un rollback

  7. #7
    Membre confirmé
    Inscrit en
    Mai 2008
    Messages
    125
    Détails du profil
    Informations personnelles :
    Âge : 42

    Informations forums :
    Inscription : Mai 2008
    Messages : 125
    Par défaut
    Merci StringBuilder, c'est vrai que utiliser le using est aussi simple que ça, je ne sais pas pourquoi je voulais me compliqué la vie... Peut être par manque d'habitude

    Je confirme les propos de BenoitM, surtout dans mon cas ou je dois archiver des emails... Si une erreur survient, je dois faire un rollback de tout ce qui a été fait auparavant...

    Merci à tous les 2 !

  8. #8
    Invité
    Invité(e)
    Par défaut
    L'explication basique de TransactionScope, c'est de permettre de faire des transactions implicites à la différence de la méthode explicite qui est par exemple l'utilisation de la méthode SqlConnection.BeginTransaction pour inititialiser une transaction.

    Comme le dit BenoitM, ça permet d'imbriquer des transactions et la transaction racine est validée que si toutes les transactions imbriquées sont validées (ça marche comme ça uniquement si on utilise les TransactionScope avec l'option TransactionScopeOptions.Required valeur pas défaut).

    AMHA, moi je préfère utiliser TransactionScope parce que c'est plus lisible pas besoin de méthodes BeginTransaction et RollBack comme c'est le cas avec les autres. Ici t'as juste besoin de ta méthode Complete qui fait office de Commit.

  9. #9
    Inactif  
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Janvier 2007
    Messages
    6 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : France

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Janvier 2007
    Messages : 6 604
    Par défaut
    Citation Envoyé par BenoitM Voir le message
    Euh je pense pas, pour moi l'avantage du TransactionScoope c'est que tu peux imbriquer des transactions
    Tu n'as pas besoin de TransactionScope si c'est pour imbriquer des transactions sur la même base, du moins sur la même connexion - suivant le type de SGBD, car certains ne supportent pas les transactions imbriquées.

    En revanche, si tu veux imbriquer des transactions de sources divers (dont certaines peuvent être "non-DB" - par exemple, il y a des Queues transactionnelles), c'est nécessaire. Par ailleurs, l'objet TransactionScope permet d'accèder facilement au service MS-DTC (Microsoft Distributed Transaction Coordinator).

  10. #10
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par Bluedeep Voir le message
    Tu n'as pas besoin de TransactionScope si c'est pour imbriquer des transactions sur la même base, du moins sur la même connexion - suivant le type de SGBD, car certains ne supportent pas les transactions imbriquées.
    D'accord avec toi que "Transactions imbriquées" ne sera pas la bonne expression à utiliser si on réfléchit au niveau SGBDR. Mais dans le code, on parle d'imbrication de transactions .

    Citation Envoyé par Bluedeep Voir le message
    Par ailleurs, l'objet TransactionScope permet d'accèder facilement au service MS-DTC (Microsoft Distributed Transaction Coordinator).
    Juste une petite précision le MS-DTC est activé seulement et uniquement si plusieurs ressources sont impliquées mais ne l'est pas si on utilise la TransactionScope uniquement avec une seule ressource telle l'accès à une seule base de données.

  11. #11
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Février 2003
    Messages
    2 196
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2003
    Messages : 2 196
    Par défaut
    Ca devient compliqué tout ça

  12. #12
    Inactif  
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Janvier 2007
    Messages
    6 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : France

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Janvier 2007
    Messages : 6 604
    Par défaut
    Citation Envoyé par h2s84 Voir le message
    Juste une petite précision le MS-DTC est activé seulement et uniquement si plusieurs ressources sont impliquées mais ne l'est pas si on utilise la TransactionScope uniquement avec une seule ressource telle l'accès à une seule base de données.
    Juste une petite précision sur la précision : le comportement est différent entre Sql Server 2005 et 2008 ! 2005 est moins bien "outillé" et "escalade à DTC" dans certains cas où 2008 ne le fait pas (notamment les cas de connexions multiples à la même base). Pour les autres versions des autres SGBD, je ne me prononcerais pas (car j'ignore la réponse).

  13. #13
    Inactif  
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Janvier 2007
    Messages
    6 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : France

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Janvier 2007
    Messages : 6 604
    Par défaut
    Citation Envoyé par BenoitM Voir le message
    Ca devient compliqué tout ça
    Toi aussi t'as remarqué !

  14. #14
    Expert confirmé
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 197
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 197
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par BenoitM Voir le message
    Euh je pense pas, pour moi l'avantage du TransactionScoope c'est que tu peux imbriquer des transactions

    Exemple tu as une Methode1 qui fait appelle à une transaction et une Méthode2 qui fait appelle aussi a une transaction
    Après tu as une Methode3 qui commence une transaction et qui appelle Methode1 et Methode2 et qui commit la transaction

    Sans transaction scope la Methode 1 et 2 auraient toute deux sauvés les modifications alors que Methode3 fait un rollback
    Hmmm, j'en perds mon latin...

    Le connecteur SQL Server pour C# ne supporte pas les transaction imbriquées et/ou parallèles (???).
    Pourtant avec VB6 avec OLEDB ça marchait parfaitement (grmpf).

    C'est moi ou y'a un bon de 20 ans en arrière là ?

    Parce que je persiste et signe : TransactionScope, de ce que j'en comprends, est un appel à des mécanismes transactionnels hors du SGBD, et ça permet surtout de faire des transactions distribuées entre plusieurs bases de données, de SGBD hétérogènes (et en effet, après lecture approfondie de la doc, ça ne rends pas l'ensemble du code transactionnel, même si c'est ce qui est maladroitement écrit dans l'article MSDN "rend un bloc transactionnel").

    SQL Server supporte parfaitement les transactions imbriquées, comme la plupart des autres SGBD, je ne comprends pas pourquoi le connecteur ne le permet pas !

    Ceci dit, on peut faire des Save() sur une transaction, ce qui permet de revenir à un point donné en cas de rollback (et donc de ne faire qu'un commit partiel). C'est moins puissant qu'une transaction imbriquée, mais dans la majorité des cas, ça répond au besoin.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    using System;
    using System.Data;
    using System.Data.Sql;
    using System.Data.SqlClient;
     
    namespace TestNestedTransaction
    {
        class Program
        {
            static void Main(string[] args)
            {
                Console.WriteLine("Simulation de transactions imbriquée (B imbriquée dans A)");
                Console.WriteLine("On utilise donc la notion de Save Point");
     
                using (SqlConnection cnx = new SqlConnection("Server=localhost\\SQLEXPRESS;Database=testlock;Trusted_Connection=True;"))
                {
                    cnx.Open();
     
                    Console.WriteLine();
                    Console.WriteLine("Cas 1 :");
                    Console.WriteLine("- La transaction A est rollbackée");
                    Console.WriteLine("- La transaction B est committée");
                    Console.WriteLine("Avec une transaction imbriquée, on s'attend à ce que tout soit rollbacké");
     
                    MonObj obj1 = new MonObj(cnx);
     
                    using (SqlTransaction tran = cnx.BeginTransaction(IsolationLevel.ReadCommitted, "TransactionA"))
                    {
                        obj1.MethodA(tran, "Cas 1, transaction A");
                        tran.Save("Après MethodA");
                        obj1.MethodB(tran, "Cas 1, transaction B");
                        tran.Rollback();
                    }
     
                    Console.WriteLine();
                    Console.WriteLine("Cas 2 :");
                    Console.WriteLine("- La transaction A est committée");
                    Console.WriteLine("- La transaction B est rollbackée");
                    Console.WriteLine("Avec une transaction imbriquée, on s'attend à ce que B soit rollbackée, mais que A soit committée");
     
                    MonObj obj2 = new MonObj(cnx);
     
                    using (SqlTransaction tran = cnx.BeginTransaction(IsolationLevel.ReadCommitted, "TransactionA"))
                    {
                        obj2.MethodA(tran, "Cas 2, transaction A");
                        tran.Save("Après MethodA");
                        obj2.MethodB(tran, "Cas 2, transaction B");
                        tran.Rollback("Après MethodA");
                        tran.Commit();
                    }
     
                    Console.WriteLine();
                    Console.WriteLine("Cas 3 :");
                    Console.WriteLine("- La transaction A est committée");
                    Console.WriteLine("- La transaction B est committée");
                    Console.WriteLine("Avec une transaction imbriquée, on s'attend à ce que les deux transactions soient committées");
     
                    MonObj obj3 = new MonObj(cnx);
     
                    using (SqlTransaction tran = cnx.BeginTransaction(IsolationLevel.ReadCommitted, "TransactionA"))
                    {
                        obj3.MethodA(tran, "Cas 3, transaction A");
                        tran.Save("Après MethodA");
                        obj3.MethodB(tran, "Cas 3, transaction B");
                        tran.Commit();
                    }
     
                    Console.WriteLine();
                    Console.WriteLine("Cas 4 :");
                    Console.WriteLine("- La transaction A est rollbackée");
                    Console.WriteLine("- La transaction B est rollbackée");
                    Console.WriteLine("Avec une transaction imbriquée, on s'attend à ce que les deux transactions soient rollbackées");
     
                    MonObj obj4 = new MonObj(cnx);
     
                    using (SqlTransaction tran = cnx.BeginTransaction(IsolationLevel.ReadCommitted, "TransactionA"))
                    {
                        obj4.MethodA(tran, "Cas 4, transaction A");
                        tran.Save("Après MethodA");
                        obj4.MethodB(tran, "Cas 4, transaction B");
                        tran.Rollback("Après MethodA");
                        tran.Rollback();
                    }
     
                    Console.WriteLine();
                    Console.WriteLine("Résultat :");
                    using (SqlCommand cmd = cnx.CreateCommand())
                    {
                        cmd.CommandText = "select id, name from test order by id";
                        SqlDataReader da = cmd.ExecuteReader();
                        while (da.Read())
                        {
                            Console.WriteLine("{0}\t{1}", da.GetInt32(0), da.GetString(1));
                        }
                    }
     
                    cnx.Close();
                }
                Console.WriteLine();
                Console.WriteLine("Fin");
                Console.ReadKey(true);
            }
        }
     
        class MonObj
        {
            SqlConnection _c;
            public MonObj(SqlConnection c)
            {
                _c = c;
            }
     
            public void MethodA(SqlTransaction tran, string name)
            {
                using (SqlCommand cmd = _c.CreateCommand())
                {
                    cmd.Transaction = tran;
                    cmd.CommandText = "insert into test (name) values (@name)";
                    cmd.Parameters.Add("name", SqlDbType.VarChar, 50).Value = name;
                    cmd.ExecuteNonQuery();
                }
            }
     
            public void MethodB(SqlTransaction tran, string name)
            {
                using (SqlCommand cmd = _c.CreateCommand())
                {
                    cmd.Transaction = tran;
                    cmd.CommandText = "insert into test (name) values (@name)";
                    cmd.Parameters.Add("name", SqlDbType.VarChar, 50).Value = name;
                    cmd.ExecuteNonQuery();
                }
            }
        }
    }
    Simulation de transactions imbriquée (B imbriquée dans A)
    On utilise donc la notion de Save Point

    Cas 1 :
    - La transaction A est rollbackée
    - La transaction B est committée
    Avec une transaction imbriquée, on s'attend à ce que tout soit rollbacké

    Cas 2 :
    - La transaction A est committée
    - La transaction B est rollbackée
    Avec une transaction imbriquée, on s'attend à ce que B soit rollbackée, mais que
    A soit committée

    Cas 3 :
    - La transaction A est committée
    - La transaction B est committée
    Avec une transaction imbriquée, on s'attend à ce que les deux transactions soien
    t committées

    Cas 4 :
    - La transaction A est rollbackée
    - La transaction B est rollbackée
    Avec une transaction imbriquée, on s'attend à ce que les deux transactions soien
    t rollbackées

    Résultat :
    3 Cas 2, transaction A
    5 Cas 3, transaction A
    6 Cas 3, transaction B

    Fin
    Honnêtement, je ne trouve pas ça plus illisible que TransactionScope, et surtout, je décide de ce qui est ou non dans ma transaction...

    Dans tous les cas, ça vaut pas de vraies transaction imbriquées.

    Et de ce que je comprends, TransactionScope ne se comporte pas mieux, ce n'est en rien des transactions imbriquées.

    Et c'est bien dommage, car l'imbrication de transactions, c'est pourtant un mécanisme formidable, d'autant qu'en interne, tous les SGBD passent leur temps à en faire.

  15. #15
    Inactif  
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Janvier 2007
    Messages
    6 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : France

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Janvier 2007
    Messages : 6 604
    Par défaut
    Citation Envoyé par StringBuilder Voir le message
    Hmmm, j'en perds mon latin...

    Le connecteur SQL Server pour C# ne supporte pas les transaction imbriquées et/ou parallèles (???).
    Si, si; d'où mon intervention, visant à "cadrer" le message de BenoitM.
    Mais tu ne peux pas, sans TransactionScope, gérer une transaction sur deux connexions.

  16. #16
    Expert confirmé
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 197
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 197
    Billets dans le blog
    1
    Par défaut
    Comment fais-tu une transaction imbriquée alors ?

    Car j'ai été obligé de tout réécrire le code ci dessus pour utiliser des Save Point, car je n'ai pas réussi à mettre en place de Nested Transaction... A chaque fois j'avais une erreur indiquant que ça ne supportait pas les transactions parallèles.

    Et vu que j'ai trouvé aucun exemple sur le net...

  17. #17
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par StringBuilder Voir le message
    .... en effet, après lecture approfondie de la doc, ça ne rends pas l'ensemble du code transactionnel, même si c'est ce qui est maladroitement écrit dans l'article MSDN "rend un bloc transactionnel").
    Peut-être que c'est moi qui n'est pas bien compris ce que tu veux dire par "ça ne rends pas l'ensemble du code transactionnel"
    Un exemple ici.

    Citation Envoyé par StringBuilder Voir le message
    Honnêtement, je ne trouve pas ça plus illisible que TransactionScope, et surtout, je décide de ce qui est ou non dans ma transaction...
    Dans l'exemple du lien que j'ai fourni. On (non Je, devrais-je dire ? ) voit bien qu'en retranscrivant ton exemple en utilisant la TransactionScope je réduis non seulement le nombre de lignes de code mais aussi l'oubli de validation de la transaction.

    Citation Envoyé par StringBuilder Voir le message
    Dans tous les cas, ça vaut pas de vraies transaction imbriquées.
    Au niveau SGDBR on est d'accord à 100% On l'utilise surtout pour partager une Transaction ambiant si elle existe avec d'autres ressources.
    Ex : Transaction SQL + Transaction WCF : si la dernière échoue tout est annulé. Et je fournis par la suite un exemple de ce qu'affirme Bluedeep en parlant de ça :
    Citation Envoyé par Bluedeep Voir le message
    Mais tu ne peux pas, sans TransactionScope, gérer une transaction sur deux connexions.

  18. #18
    Expert confirmé
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 197
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 197
    Billets dans le blog
    1
    Par défaut
    Je viens de re-tester les transactions imbriquées, et pas moyen :

    Nom : nestedtransaction.PNG
Affichages : 85
Taille : 19,4 Ko

    Pourtant, en ASP des années 1990 (donc VBScript) :
    http://www.devguru.com/technologies/...egintrans.html
    This method can also be used to return a long value that is the level of nested transactions. A nested transaction is simply a transaction that occurs within a transaction. A top level transaction has a return value of 1 (one). Each additional level increments by one (the second level returns a 2, etc.).
    Sinon, le code avec TransactionScope n'est pas plus court...

    Ci dessous la version transcrite avec SqlTransaction. Elle ne fait pas une seule ligne de plus.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
     
     
                //Create and open the SQL connection.  The work done on this connection will be a part of the transaction created by the TransactionScope
                using (SqlConnection myConnection = new SqlConnection("server=(local)\\SQLExpress;Integrated Security=SSPI;database=northwind"))
                {
                    myConnection.Open();
                    using (SqlCommand myCommand = new SqlCommand())
                    {
                        myCommand.Connection = myConnection;
     
                        using (SqlTransaction tran = myConnection.BeginTransaction())
                        {
                            //Restore database to near it's original condition so sample will work correctly.
                            myCommand.CommandText = "DELETE FROM Region WHERE (RegionID = 100) OR (RegionID = 101)";
                            myCommand.ExecuteNonQuery();
     
                            //Insert the first record.
                            myCommand.CommandText = "Insert into Region (RegionID, RegionDescription) VALUES (100, 'MidWestern')";
                            myCommand.ExecuteNonQuery();
     
                            //Insert the second record.
                            myCommand.CommandText = "Insert into Region (RegionID, RegionDescription) VALUES (101, 'MidEastern')";
                            myCommand.ExecuteNonQuery();
     
                            myConnection.Close();
     
                            //Call complete on the TransactionScope or not based on input
                            ConsoleKeyInfo c;
                            while (true)
                            {
                                Console.Write("Complete the transaction scope? [Y|N] ");
                                c = Console.ReadKey();
                                Console.WriteLine();
     
                                if ((c.KeyChar == 'Y') || (c.KeyChar == 'y'))
                                {
                                    // Commit the transaction
                                    tran.Commit();
                                    break;
                                }
                                else if ((c.KeyChar == 'N') || (c.KeyChar == 'n'))
                                {
                                    break;
                                }
                            }
                        }
                    }
                }
    Si vous trouvez qu'il y a trop d'indentation, vous pouvez vous amuser à enlever des using, en effet, pour un exemple simple comme ça, un seul using sur la connexion est réellement utile.

  19. #19
    Expert confirmé
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 197
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 197
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par h2s84 Voir le message
    On l'utilise surtout pour partager une Transaction ambiant si elle existe avec d'autres ressources.
    Ex : Transaction SQL + Transaction WCF : si la dernière échoue tout est annulé. Et je fournis par la suite un exemple de ce qu'affirme Bluedeep en parlant de ça :
    Oui, dans ce cas, TransactionScope est très utile.
    Mais d'après le sujet initial, le problème ne semble pas se situer autour du fait qu'il y a plusieurs sources de données, mais plutôt qu'il y a plusieurs thread qui tapent dans la même source. Et là, les SqlTransaction sont tout à fait indiquées.

  20. #20
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par StringBuilder Voir le message
    Si vous trouvez qu'il y a trop d'indentation, vous pouvez vous amuser à enlever des using, en effet, pour un exemple simple comme ça, un seul using sur la connexion est réellement utile.
    Bah ! Ton code marche ouais et elle ne fait pas une seule ligne de plus parce que tout simplement tu as préféré bénéficier du Dispose de la connexion pour "rollbacker" la transaction et ainsi ne pas avoir à écrire la ligne de plus qui aurait fait la différence dont je te parlais. As-tu pensé aux autres développeurs débutants qui viendront après toi qui se mettront à chercher où se trouve la ligne tran.Rollback(); ? T'imagines les 5 minutes précieuses que tu leur fais perdre. OK je déconne mais ...

Discussions similaires

  1. Redhat-9 changer le path des databases
    Par jean christophe dans le forum Installation
    Réponses: 7
    Dernier message: 30/05/2003, 17h53
  2. [BDE] Ou peut-on telecharger le Borland Database Engine?
    Par Robert A. dans le forum Autres SGBD
    Réponses: 2
    Dernier message: 27/05/2003, 10h01
  3. Blob (interbase) d'une Database à l'autre
    Par TOM-Z dans le forum XMLRAD
    Réponses: 2
    Dernier message: 18/05/2003, 21h57
  4. Multithreading sous HP Ux 11
    Par pykoon dans le forum Autres éditeurs
    Réponses: 1
    Dernier message: 18/10/2002, 23h36
  5. Tutoriels et liens pour le Borland Database Engine
    Par Community Management dans le forum Paradox
    Réponses: 0
    Dernier message: 25/03/2002, 10h23

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo