L'essence des transactions Spring est en fait la prise en charge des transactions par la base de données, Spring ne peut pas fournir de fonctions de transaction. Pour une base de données d'opérations JDBC pure, si vous souhaitez utiliser des transactions, vous pouvez suivre les étapes suivantes :
Obtenir la connexion Connection con = DriverManager.getConnection()
Ouvrir la transaction con.setAutoCommit(true/false);
Exécuter CRUD
Commit transaction/rollback transaction con.commit () / con.rollback();
Fermez la connexion conn.close();
Après avoir utilisé la fonction de gestion des transactions de Spring, nous Impossible ensuite d'écrire le code des étapes 2 et 4, mais il sera automatiquement complété par Spirng .Alors Spring est Comment ouvrir et fermer les transactions avant et après le CRUD que nous écrivons ?Pour résoudre ce problème, nous pouvons comprendre le principe de mise en œuvre de la gestion des transactions de Spring dans son ensemble. Présentons brièvement la méthode d'annotation à titre d'exemple
. <.>Fichier de configurationActivez l'annotationDriver et marquez les classes et méthodes pertinentes avec l'annotation @Transactional
est présentée dans le tableau suivant :
Nom de la constante | Explication de la constante |
PROPAGATION_REQUIRED | Prend en charge la transaction en cours S'il n'y a pas de transaction en cours, créez une nouvelle transaction. . Il s'agit du choix le plus courant et constitue la propagation des transactions par défaut de Spring. |
PROPAGATION_REQUIRES_NEW | Nouvelle transaction, s'il existe actuellement une transaction, Suspendre la transaction en cours. La transaction nouvellement créée n'aura rien à voir avec la transaction suspendue. Ce sont deux transactions indépendantes. Après l'échec de la transaction externe et son annulation, les résultats de l'exécution de la transaction interne ne peuvent pas être annulés. "http: //www.php.cn/php/php-tp-throw.html" target="_blank">Lance une exception, capturée par la transaction externe, ou ne traite pas l'opération de restauration |
PROPAGATION_SUPPORTS | Prend en charge la transaction en cours s'il n'y a actuellement aucune transaction. , il sera exécuté de manière non transactionnelle. |
PROPAGATION_MANDATORY | Prend en charge la transaction en cours s'il n'y a pas transaction en cours, une exception est levée. |
PROPAGATION_NOT_SUPPORTED | Effectuer des opérations de manière non transactionnelle if S'il y a actuellement une transaction, la transaction en cours est suspendue. |
PROPAGATION_NEVER | Exécuter en mode non transactionnel, si le courant Si une transaction existe, une exception est levée. |
PROPAGATION_NESTED | Si une transaction active existe, s'exécute dans une transaction imbriquée. S'il n'y a aucune transaction active, l'attribut REQUIRED est exécuté. Il utilise une seule transaction avec plusieurs points de sauvegarde pouvant être annulés. L'annulation des transactions internes n'affectera pas les transactions externes. Cela ne fonctionne que sur le gestionnaire de transactions DataSourceTransactionManager. |
隔离级别 | 隔离级别的值 | 导致的问题 |
Read-Uncommitted | 0 | 导致脏读 |
Read-Committed | 1 | 避免脏读,允许不可重复读和幻读 |
Repeatable-Read | 2 | 避免脏读,不可重复读,允许幻读 |
Serializable | 3 | 串行化读,事务只能一个一个执行,避免了脏读、不可重复读、幻读。执行效率慢,使用时慎重 |
Lecture sale : une transaction a ajouté, supprimé ou modifié des données, mais elle n'a pas été soumise. Une autre transaction peut lire les données non validées. Si la première transaction est annulée à ce moment-là, la deuxième transaction lira les données sales.
Lecture non répétable : deux opérations de lecture se sont produites dans une transaction. Entre la première opération de lecture et la deuxième opération, une autre transaction a modifié les données. À ce moment, les données lues deux fois sont incohérentes.
Lecture fantôme : la première transaction regroupe les modifications d'une certaine plage de données, et la deuxième transaction ajoute une donnée à cette plage. À ce moment, la première transaction perdra la modification des données nouvellement ajoutées. .
Résumé :
Plus le niveau d'isolement est élevé, plus les données peuvent être complètes et cohérentes, mais plus l'impact sur les performances de concurrence est grand.
Le niveau d'isolement par défaut de la plupart des bases de données est Lecture validée, comme SqlServer, Oracle
Le niveau d'isolement par défaut de quelques bases de données est : Lecture répétable, telle que : MySQL InnoDB
常量 | 解释 |
ISOLATION_DEFAULT | 这是个 PlatfromTransactionManager 默认的隔离级别,使用数据库默认的事务隔离级别。另外四个与 JDBC 的隔离级别相对应。 |
ISOLATION_READ_UNCOMMITTED | 这是事务最低的隔离级别,它充许另外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读。 |
ISOLATION_READ_COMMITTED | 保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。 |
ISOLATION_REPEATABLE_READ | 这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。 |
ISOLATION_SERIALIZABLE | 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。 |
Grâce aux connaissances théoriques ci-dessus, nous avons une compréhension approximative de certains attributs et caractéristiques des transactions de base de données et des transactions printanières, pour comprendre en profondeur les scénarios de transactions imbriquées. mécanisme de propagation des transactions printanières.
Supposons que la méthode A() du service de transaction externe A appelle la méthode B() du service interne B
PROPAGATION_REQUIRED (printemps par défaut)
Si le niveau de transaction de ServiceB.methodB() est défini comme PROPAGATION_REQUIRED, alors spring a déjà initié une transaction lors de l'exécution de ServiceA.methodA(). À ce moment, ServiceB.methodB() est appelé et ServiceB.methodB() le voit. est déjà en cours d'exécution dans ServiceA. Dans la transaction de methodA(), aucune nouvelle transaction ne sera initiée.
Si ServiceB.methodB() constate qu'il n'est pas dans une transaction lors de son exécution, il s'attribuera une transaction pour lui-même.
De cette façon, si une exception se produit n'importe où dans ServiceA.methodA() ou ServiceB.methodB(), la transaction sera annulée.
PROPAGATION_REQUIRES_NEW
Par exemple, nous concevons le niveau de transaction de ServiceA.methodA() comme étant PROPAGATION_REQUIRED et le niveau de transaction de ServiceB.methodB() comme étant PROPAGATION_REQUIRES_NEW .
Ensuite, lorsque ServiceB.methodB() sera exécuté, la transaction où se trouve ServiceA.methodA() sera suspendue et ServiceB.methodB() démarrera une nouvelle transaction, en attendant ServiceB.methodB() après la transaction est terminée, elle continue son exécution.
La différence entre celui-ci et PROPAGATION_REQUIRED est le degré d'annulation de la transaction. Étant donné que ServiceB.methodB() démarre une nouvelle transaction, il existe deux transactions différentes. Si ServiceB.methodB() a été soumis, alors ServiceA.methodA() échoue et revient en arrière, mais ServiceB.methodB() ne revient pas en arrière. Si ServiceB.methodB() ne parvient pas à revenir en arrière, si l'exception levée est interceptée par ServiceA.methodA(), la transaction ServiceA.methodA() peut toujours être soumise (cela dépend principalement si l'exception levée par B est une exception que A va revenir en arrière) .
PROPAGATION_SUPPORTS
Supposons que le niveau de transaction de ServiceB.methodB() est PROPAGATION_SUPPORTS, puis lorsque ServiceB.methodB() est exécuté, s'il s'avère que ServiceA. methodA() a été Lorsqu'une transaction est ouverte, rejoignez la transaction en cours S'il s'avère que ServiceA.methodA() n'ouvre pas la transaction, il n'ouvrira pas la transaction elle-même. À l’heure actuelle, le caractère transactionnel de la méthode interne dépend entièrement de la transaction la plus externe.
PROPAGATION_NESTED
Maintenant, la situation devient plus compliquée. L'attribut de transaction de ServiceB.methodB() est configuré comme PROPAGATION_NESTED. À ce stade, il y aura Comment collaborer. ? ServiceB#methodB En cas d'annulation, la transaction interne (c'est-à-dire ServiceB#methodB) sera restaurée vers le SavePoint avant son exécution, tandis que la transaction externe (c'est-à-dire ServiceA#methodA) peut être traitée des deux manières suivantes :
a. Capturez les exceptions et exécutez la logique de branche d'exception
void methodA() { try { ServiceB.methodB(); } catch (SomeException) { // 执行其他业务, 如 ServiceC.methodC(); } }
Cette méthode est également la partie la plus précieuse des transactions imbriquées. Elle a pour effet d'exécuter une branche. ServiceC est exécuté methodC() et ServiceB.methodB est revenu au SavePoint avant son exécution, donc aucune donnée sale ne sera générée (équivalent au fait que cette méthode ne sera jamais exécutée). Cette fonctionnalité peut être utilisée dans certaines entreprises spéciales. et PROPAGATION_REQUIRED Ni PROPAGATION_REQUIRES_NEW ni PROPAGATION_REQUIRES_NEW ne peuvent faire cela.
b. Le code d'annulation/de validation de la transaction externe n'apporte aucune modification, puis si la transaction interne (ServiceB#methodB) est annulée, alors ServiceB.methodB revient d'abord au SavePoint avant son exécution (dans n'importe quel Dans ce cas), la transaction externe (c'est-à-dire ServiceA#methodA) décidera de valider ou d'annuler en fonction de la configuration spécifique
Les trois autres attributs de propagation de transaction ne sont fondamentalement pas utilisés et ne seront pas analysés ici.
Pour les endroits où des transactions doivent être utilisées dans le projet, je recommande aux développeurs de toujours utiliser l'interface TransactionCallback de Spring pour implémenter les transactions. N'utilisez pas aveuglément les annotations de transaction Spring si vous. doit utiliser Remarque, vous devez avoir une compréhension détaillée du mécanisme de propagation des transactions Spring et du niveau d'isolement, sinon des effets inattendus peuvent survenir.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!