390 votes

Spring - @Transactional - Que se passe-t-il en arrière-plan ?

Je veux savoir ce qui se passe réellement quand on annote une méthode avec @Transactional ? Bien sûr, je sais que Spring va envelopper cette méthode dans une transaction.

Mais, j'ai les doutes suivants :

  1. J'ai entendu dire que le printemps crée un classe proxy ? Quelqu'un peut-il m'expliquer cela en détail ? profondeur . Qu'est-ce qui réside réellement dans cette classe proxy ? Qu'arrive-t-il à la classe réelle ? Et comment puis-je voir la classe proxiée créée par Spring ?
  2. J'ai également lu dans les documents de Spring que :

Note : Comme ce mécanisme est basé sur des proxies, seuls les appels de méthodes "externes" arrivant par le biais du proxy seront interceptés. . Cela signifie que l'"auto-invocation", c'est-à-dire une méthode de l'objet cible appelant une autre méthode de l'objet cible, ne conduira pas à une transaction réelle au moment de l'exécution, même si la méthode invoquée est marquée avec le symbole @Transactional !

Source : http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html

Pourquoi seuls les appels de méthodes externes seront sous Transaction et non les méthodes d'auto-invocation ?

2 votes

La discussion pertinente est ici : stackoverflow.com/questions/3120143/

284voto

Rob H Points 5599

C'est un sujet important. Le document de référence de Spring y consacre plusieurs chapitres. Je vous recommande de lire ceux sur Programmation orientée aspects y Transactions Le support déclaratif des transactions de Spring est basé sur la POA.

Mais à un niveau très élevé, Spring crée des proxies pour les classes qui déclarent @Transactional sur la classe elle-même ou sur les membres. Le proxy est le plus souvent invisible au moment de l'exécution. Il permet à Spring d'injecter des comportements avant, après ou autour des appels de méthode dans l'objet proxyé. La gestion des transactions n'est qu'un exemple des comportements qui peuvent être injectés. Les contrôles de sécurité en sont un autre. Et vous pouvez également fournir vos propres comportements, pour des choses comme la journalisation. Ainsi, lorsque vous annotez une méthode avec @Transactional En effet, Spring crée dynamiquement un proxy qui implémente la ou les mêmes interfaces que la classe que vous annotez. Et lorsque les clients font des appels à votre objet, les appels sont interceptés et les comportements injectés via le mécanisme de proxy.

Les transactions dans EJB fonctionnent de manière similaire, d'ailleurs.

Comme vous l'avez observé, à travers, le mécanisme de proxy ne fonctionne que lorsque les appels proviennent d'un objet externe. Lorsque vous effectuez un appel interne à l'objet, vous effectuez en réalité un appel par le biais du mécanisme de proxy. this ce qui permet de contourner le proxy. Il existe toutefois des moyens de contourner ce problème. J'explique une approche dans ce message du forum dans lequel j'utilise un BeanFactoryPostProcessor pour injecter une instance du proxy dans les classes "auto-référencées" au moment de l'exécution. Je sauvegarde cette référence dans une variable membre appelée me . Ensuite, si j'ai besoin d'effectuer des appels internes qui nécessitent un changement de l'état de la transaction du thread, je dirige l'appel à travers le proxy (par exemple me.someMethod() .) Le post du forum explique plus en détail.

Notez que le BeanFactoryPostProcessor Le code serait un peu différent aujourd'hui, puisqu'il a été écrit à l'époque de Spring 1.x. Mais j'espère que cela vous donnera une idée. J'ai une version mise à jour que je pourrais probablement mettre à disposition.

7 votes

>> Le proxy est pratiquement invisible au moment de l'exécution. Je suis curieux de les voir :) Repos votre réponse était très complète. C'est la deuxième fois que vous m'aidez Merci pour toute cette aide.

19 votes

Pas de problème. Vous pouvez voir le code proxy si vous passez à travers avec un débogueur. C'est probablement le moyen le plus simple. Il n'y a pas de magie, ce sont juste des classes dans les packages Spring.

0 votes

Et si la méthode qui a l'annotation @Transaction implémente une interface, Spring utilisera l'API de proxy dynamique pour injecter la transactionnalisation et l'annotation @Transaction. no utiliser des proxies. Je préfère que mes classes transactionnelles mettent en œuvre des interfaces dans tous les cas.

214voto

skaffman Points 197885

Lorsque Spring charge vos définitions de bean, et qu'il a été configuré pour rechercher les éléments suivants @Transactional il créera ces annotations objets proxy autour de votre haricot . Ces objets proxy sont des instances de classes qui sont générées automatiquement au moment de l'exécution. Le comportement par défaut de ces objets proxy lorsqu'une méthode est invoquée est d'invoquer la même méthode sur le bean "cible" (c'est-à-dire votre bean).

Cependant, les proxies peuvent également être fournis avec des intercepteurs, et lorsqu'ils sont présents, ces intercepteurs seront invoqués par le proxy avant qu'il n'invoque la méthode de votre bean cible. Pour les beans cibles annotés avec @Transactional Spring va créer un TransactionInterceptor et le passe à l'objet proxy généré. Ainsi, lorsque vous appelez la méthode à partir du code client, vous appelez la méthode sur l'objet proxy, qui invoque d'abord l'objet TransactionInterceptor (qui commence une transaction), qui à son tour invoque la méthode sur votre bean cible. Lorsque l'invocation se termine, le TransactionInterceptor commet/annule la transaction. C'est transparent pour le code client.

Pour ce qui est de la "méthode externe", si votre bean invoque une de ses propres méthodes, il ne le fera pas via le proxy. Rappelez-vous que Spring enveloppe votre bean dans le proxy, votre bean n'en a aucune connaissance. Seuls les appels provenant de l'"extérieur" de votre bean passent par le proxy.

Est-ce que ça aide ?

41 votes

>Rappelez-vous, Spring enveloppe votre bean dans le proxy, votre bean n'en a aucune connaissance. Ça a tout dit. Quelle bonne réponse. Merci de m'avoir aidé.

1 votes

Excellente explication, pour le proxy et les intercepteurs. Maintenant je comprends que Spring implémente un objet proxy pour intercepter les appels vers un bean cible. Merci !

1 votes

Je pense que vous essayez de décrire cette image de la documentation de Spring et voir cette image m'aide beaucoup : docs.spring.io/spring/docs/4.2.x/spring-framework-reference/

54voto

progonkpa Points 763

En tant que personne visuelle, j'aime apporter ma contribution avec un diagramme de séquence du modèle proxy. Si vous ne savez pas comment lire les flèches, je lis la première comme ceci : Client exécute Proxy.method() .

  1. Le client appelle une méthode sur la cible de son point de vue, et est intercepté silencieusement par le proxy.
  2. Si un aspect before est défini, le proxy l'exécutera
  3. Ensuite, la méthode réelle (cible) est exécutée.
  4. L'after-returning et l'after-throwing sont des aspects facultatifs qui sont exécutés après le retour de la méthode et/ou si la méthode lève une exception
  5. Après cela, le proxy exécute l'aspect after (s'il est défini)
  6. Enfin, le proxy retourne au client appelant

Proxy Pattern Sequence Diagram (J'ai été autorisé à publier la photo à condition de mentionner son origine. Auteur : Noel Vaes, site web : https://www.noelvaes.eu )

42voto

RoshanKumar Mutha Points 669

La réponse la plus simple est :

Quelle que soit la méthode que vous déclarez @Transactional la limite de la transaction commence et la limite se termine lorsque la méthode se termine.

Si vous utilisez l'appel JPA, alors tous les commits sont avec dans ce périmètre de transaction .

Disons que vous sauvegardez l'entité 1, l'entité 2 et l'entité 3. Maintenant, pendant la sauvegarde de l'entité 3, un l'exception se produit alors, comme l'entité 1 et l'entité 2 sont dans la même transaction, l'entité 1 et l'entité 2 seront retour en arrière avec l'entité 3.

Transaction :

  1. entité1.save
  2. entité2.save
  3. entité3.save

Toute exception entraînera l'annulation de toutes les transactions JPA avec la base de données, alors que les transactions JPA sont utilisées en interne par Spring.

5voto

Marco Behler Points 2694

Toutes les réponses existantes sont correctes, mais je sens que je ne peux pas donner juste ce sujet complexe.

Pour une explication complète et pratique, vous pouvez consulter ce document. Spring @Transactional en profondeur qui fait de son mieux pour couvrir la gestion des transactions en ~4000 mots simples, avec de nombreux exemples de code.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X