1. Principes de base des transactions
L'essence des transactions Spring est en fait la prise en charge de la base de données pour les transactions. Sans support de transaction de base de données, Spring ne peut pas fournir de fonctions de transaction. Pour les bases de données de fonctionnement JDBC pures, si vous souhaitez utiliser des transactions, vous pouvez suivre les étapes suivantes:
1. Obtenez la connexion de connexion Con = driverManager.getConnection ()
2. Ouvrez la transaction con.setAutoCommit (true / false);
3. Exécuter Crud
4. Commit Transaction / Rollback Transaction Con.Commit () / Con.Rollback ();
5. Fermez la connexion conn.close ();
Après avoir utilisé la fonction de gestion des transactions de Spring, nous ne pouvons plus écrire le code dans les étapes 2 et 4, mais nous sera automatiquement effectué par Spirng. Alors, comment le printemps s'ouvre-t-il et ferme-t-il les transactions avant et après le crud que nous écrivons? En résolvant ce problème, nous pouvons comprendre le principe de mise en œuvre de la gestion des transactions de Spring dans son ensemble. Permettez-moi de présenter brièvement la méthode d'annotation comme exemple
1. Allumez le pilote d'annotation dans le fichier de configuration et identifiez-le en annotant le @transactionnel sur les classes et méthodes pertinentes.
2. Lorsque le printemps commencera, il analysera et générera des haricots connexes. À l'heure actuelle, il vérifiera les classes et les méthodes avec des annotations pertinentes, et générera un proxy pour ces classes et méthodes, et effectuera une injection de configuration connexe en fonction des paramètres pertinents de @transaction, afin que les transactions pertinentes soient traitées pour nous dans le proxy (démarrage des transactions normales et des transactions de retour en arrière d'exception).
3. Commission de transaction et le recul de la couche réelle de la base de données sont implémentées via le binlog ou le journal de rétablissement.
2. Propriétés de propagation des transactions de printemps
L'attribut de propagation dite des transactions Spring définit comment Spring devrait gérer le comportement de plusieurs transactions lorsqu'ils existent en même temps. Ces propriétés sont définies dans TransactionDefinition. Les constantes spécifiques sont expliquées dans le tableau suivant:
Iii. Niveau d'isolement de la base de données
Dirty Reading: Une transaction ajoute, supprime et modifie les données, mais n'est pas engagée, et une autre transaction peut lire des données non engagées. Si la première transaction recule à ce moment, la deuxième transaction lit les données sales.
Pas de lecture répétitive: deux opérations de lecture se produisent dans une seule transaction. Entre la première opération de lecture et la deuxième opération, l'autre transaction modifie les données. À l'heure actuelle, les données lues deux fois sont incohérentes.
Lecture fantastique: la première transaction modifie les données dans une certaine plage de lots, et la deuxième transaction ajoute une données à cette plage. À l'heure actuelle, la première transaction perdra la modification des données nouvellement ajoutées.
Résumez :
Plus le niveau d'isolement est élevé, plus il peut assurer l'intégrité et la cohérence des données, mais plus l'impact sur les performances de la concurrence est grande.
Le niveau d'isolement par défaut de la plupart des bases de données est lue commandée, comme SQLServer et Oracle
Le niveau d'isolement par défaut de quelques bases de données est: Readable Lire par exemple: MySQL InNODB
Iv. Niveau d'isolement au printemps
V. nidification des transactions
Grâce aux connaissances théoriques ci-dessus, nous comprenons à peu près certains attributs et caractéristiques des transactions de base de données et des transactions Spring. Ensuite, nous analysons certains scénarios de transaction imbriqués pour comprendre profondément le mécanisme de la propagation des transactions printanières.
Supposons que la méthode a () du service de transaction extérieure A appelle la méthode b () du service intérieur b
Propagation_Required (Spring par défaut)
Si le niveau de transaction de ServiceB.Methodb () est défini comme Propagation_Required, alors lorsque le Servicea.Methoda () est exécuté, la transaction a déjà commencé au printemps. À l'heure actuelle, ServiceB.Methodb () est appelé. ServiceB.Methodb () voit qu'il s'exécute à l'intérieur de la transaction de Servicea.Methoda (), et aucune nouvelle transaction n'est démarrée.
Si ServiceB.Methodb () est en cours d'exécution, il attribuera une transaction à lui-même.
De cette façon, si une exception se produit dans Servicea.Methoda () ou n'importe où dans ServiceB.Methodb (), la transaction sera annulée.
Propagation_requires_new
Par exemple, nous avons conçu que Servicea.Methoda () a un niveau de transaction de propagation_reQuired, et ServiceB.Methodb () a un niveau de transaction de propagation_requires_new.
Ensuite, lorsque le serviceB.Methodb () est exécuté, la transaction où se trouve Servicea.Methoda () sera suspendue, et ServiceB.Methodb () démarrera une nouvelle transaction et continuera d'exécuter une fois la transaction ServiceB.Methodb ().
La différence entre ses transactions et sa propagation_requeed est le degré de recul de la transaction. Étant donné que ServiceB.Methodb () est une nouvelle transaction, il existe deux transactions différentes. Si ServiceB.Methodb () a été soumis, Servicea.Methoda () ne parvient pas à randonner, ServiceB.Methodb () ne sera pas retourné. Si ServiceB.Methodb () ne revient pas, si l'exception lancée par Servicea.Methoda () est capturée, la transaction Servicea.Methoda () peut toujours être soumise (dépend principalement de la question de savoir si l'exception lancée par B est une exception qu'un Rollback).
Propagation_supports
En supposant que le niveau de transaction de ServiceB.Methodb () est Propagation_Supports, lorsqu'il est exécuté sur ServiceB.Methodb (), s'il est constaté que Servicea.Methoda () a ouvert une transaction, il rejoindra la transaction actuelle. S'il est constaté que Servicea.Methoda () n'a pas démarré la transaction, il ne démarrera pas la transaction elle-même. À l'heure actuelle, la transactionnalité de la méthode interne dépend entièrement de la transaction la plus externe.
Propagation_nesed
La situation devient plus compliquée maintenant. La propriété de transaction de ServiceB.Methodb () est configurée comme propagation_nesed. Comment les deux coopéreront-ils pour le moment? ServiceB # MethodB si Rollback, alors les transactions internes (c'est-à-dire ServiceB # MethodB) se retourneront sur SavePoint avant l'exécution, tandis que les transactions externes (c'est-à-dire Servicea # Methoda) peuvent avoir les deux façons de gérer:
un. Catch des exceptions et exécutez la logique de la branche des exceptions
void methoda () {try {ServiceB.Methodb (); } catch (SomeException) {// Exécuter d'autres entreprises, telles que ServiceC.Methodc (); }} Cette méthode est également la chose la plus précieuse concernant les transactions imbriquées. Il joue le rôle de l'exécution des branches. Si ServiceB.Methodb échoue, ServiceC.Methodc () est exécuté et ServiceB.Methodb est revenu au point de sauvegarde avant son exécution, donc aucune donnée sale n'est générée (équivalent à cette méthode qui ne soit jamais exécutée). Cette fonctionnalité peut être utilisée dans certains services spéciaux, et ni Propagation_Required ni propagation_requires_new ne peuvent le faire.
né Le code Rollback / Commit de transaction externe ne fait aucune modification. Si la transaction interne (ServiceB # MethodB) Rollback, alors d'abord ServiceB.Methodb revient au point de sauvegarde avant son exécution (dans tous les cas), et la transaction externe (c'est-à-dire Servicea # Methoda) décidera si elle s'engage ou rollback en fonction de la configuration spécifique.
Les trois autres attributs de propagation des transactions sont fondamentalement inefficaces, donc aucune analyse n'est effectuée ici.
6. Résumé
Pour les endroits où les transactions sont nécessaires dans le projet, je suggère que les développeurs devraient utiliser l'interface TransactionCallback de Spring pour implémenter les transactions. N'utilisez pas aveuglément les annotations de transaction Spring. Si vous devez utiliser des annotations, vous devez avoir une compréhension détaillée du mécanisme de propagation et du niveau d'isolement des transactions de ressort, sinon des effets inattendus peuvent se produire.