9
votes

Pourquoi CMT s'engage-t-il à la sortie de la méthode EJB lorsque l'attribut de transaction est "requis"?

Je trouve constamment que ma transaction déjà existante se soit engagée à l'intérieur de toute méthode d'un EJB marqué @ ejb.transaction type = "requis" . Cela peut-il être correct?

Mon attente est une EJB "nécessitant" une transaction signifie: s'il y en y en a un déjà là, il le laissera poliment non engagé lorsqu'il sera fait de sorte que quiconque invoqué commence () peut continuer à l'utiliser pour d'autres opérations avant d'invoquer commit () ou Rollback () . [Bien sûr, s'il n'y avait pas de transaction en premier lieu, la méthode EJB invoquerait les deux commencer () et commit () / Rollback () < / code>.]

mon espoir est faux, ou devrais-je rechercher un bug de configuration?

Il pourrait être pertinent d'ajouter que j'utilise Hibernate 3 à l'intérieur de l'EJB. J'obtenue une maîtrise utilisateur avant d'appeler la méthode EJB. L'enveloppe générée par l'EJB invoque servertransaction.commit () à la sortie, quel hibernate gare et utilise la possibilité de fermer sa session. L'erreur que je reçois est une exception de chargement paresseux hibernate, car la session est fermée lorsque j'essaie d'accéder aux getters sur un objet persistant hibernate. Donc, techniquement, je ne suis pas sûr que je ne suis sûr que si le ServerTransaction.commit () j'ai observé nécessairement commis le usertransaction i démarré (peut-être serveurTransaction.commit () < / code> ne suivra pas toujours avec une "vraie" commit?), mais si ce n'est pas le cas - alors sur quelle base la clôture de la session?

Mise à jour: Je crois que mes hypothèses ci-dessus étaient correctes, mais mes observations étaient un peu désactivées. Voir ci-dessous pour ma réponse auto-fournie.


4 commentaires

" S'il y en a un déjà là, il le laissera poliment non engagée. " Êtes-vous sûr de votre perception ici? De votre réponse acceptée, " le usertransaction i démarré est resté ouvert, mais CMT a créé une nouvelle transaction à l'entrée de la méthode EJB, malgré l'attribut" Requis ". " Ceci est une tentative de créer une autre transaction imbriquée et devrait plutôt provoquer une exception comme - javax.transaction.notsupportedexception: transaction imbriquée non prise en charge. , puisque les transactions imbriquées ne sont pas prises en charge dans Java Ee. Je me suis complètement induit sur ce que j'ai déjà connu sur CMT et BMT.


Pouvez-vous vous souvenir du scénario de test utilisé il y a quatre?


@TILY - Je me souviens de valider de multiples façons que matransaction est restée ouverte et que la transaction CMT a été commise à la sortie de l'EJB gérée par le conteneur. Cette compréhension m'a permis d'accueillir la situation avec succès, sinon gracieusement. Je n'ai jamais rien trouvé pour indiquer que WL avait été prouvé de se comporter autrement (noter que les tests cités par Davidblevens utilisés obligatoires selon lui, non requis comme si mon cas). C'était il y a 3-4 contrats, donc je ne peux donc pas vous donner plus que cela, désolé.


Je m'excuse pour l'orthographe @davidblevins. Apparemment, je ne peux plus le réparer car 5 minutes sont passées.


4 Réponses :


0
votes

Voilà comment fonctionne des transactions gérées par CMT. Le conteneur engage automatiquement la transaction lorsque la méthode commerciale revient. Si vous n'utilisez pas ce comportement, utilisez BMT au lieu de CMT.


5 commentaires

Merci pour la réponse KRIS. Mais cela semble être un moyen totalement non utile pour CMT se comporter lorsque "requis" ou "supporté" est spécifié, lorsqu'il y a déjà une transaction en cours. Je ne trouve aucune explication des transactions CMT qui le confirme. Auriez-vous un lien, par hasard?


"En règle générale, le conteneur commence une transaction immédiatement avant la démarrage d'une méthode de haricot d'entreprise. Il engage la transaction juste avant la sortie de la méthode. Chaque méthode peut être associée à une transaction unique. Des transactions imbriquées ou multiples ne sont pas autorisées dans une méthode." - Copié À partir d'ici: Java.sun.com/j2ee/Tutorial/1_3 -FCS / DOC / transaction3.html


Oui, je relisais simplement ce paragraphe exact. (Désolé, je ne peux pas uppoter.) Je dois admettre que cela n'appelle aucune différence en fonction de l'attribut de transaction. Pour moi, il s'agit d'une omission flagrante et rend 50% des scénarios de transaction que je peux penser à quasi non imprimable. Peut-être que je ne fais tout simplement pas "l'obtenir" :).


Je pense que je vais essayer de migrer cette application Legacy, je me débats à l'écart de CMT. Pour moi, la méthode EJB est typiquement trop granuleuse une péril de transaction de toute façon, et désactive également un chargement paresseux Hibernate dans la couche d'application, car elle tombe généralement en dehors de la transaction. J'ai vu des suggestions selon lesquelles on démarre et finit la transaction dans un filtre de servlet, qui est agréable pour les scénarios «commettez» de «commit» heureux, mais je préfère aborder des scénarios de «restauration» dans la couche de contrôle où la messagerie d'erreur est la plus proprement et manipulé de manière flexible. Commentaires sur cette stratégie, n'importe qui?


Je crois maintenant que mes attentes initiales étaient correctes et que la réponse KRIS a donné n'est pas, bien que sa réponse soit basée sur une image que j'ai dessinée à la fois partielle et incorrecte. Voir ci-dessous pour ma conclusion.



1
votes

Une inspection plus proche révèle une réponse différente que suggérée ci-dessus. Ce que je constate réellement, c'est que l'utilisateurTransaction que j'ai commencé est restée ouverte, mais CMT a créé une nouvelle transaction à l'entrée de la méthode EJB, malgré l'attribut "requis".

Je crois que cela se passe parce que j'ai enfreint les règles. :) Vous n'êtes pas censé accéder à l'API UserTransAction lors de l'utilisation de CMT. CMT a heureusement ignoré mon utilisateurTransaction et a démarré le sien, après avoir pris sa place comme arbitre de toutes les limites de transaction. Depuis que cela a commencé la transaction, cela l'a également commis, et bien sûr, a laissé mon usertransaction intact.

semble fragile et stupide pour moi, peut-être une opinion naïve, mais semble compatible avec les "règles" comme je les lis. Je ne sais pas pourquoi CMT choisit de ne pas jouer sympa avec destransactions utilitaires commençant à un niveau supérieur. Peut-être de forcer les développeurs à «faire la bonne chose J2EE» et à créer une autre couche de session pour gérer le contexte de transaction plus large. Cela fonctionnerait car la CMT gérerait la transaction externe et irait donc bien avec l'enrôlant toutes les transactions internes, et je crois en un tel cas, la transaction «parapluie» ne serait pas commise par les EJB intérieures; CMT attendrait que la transaction extérieure se termine, puis commettre le tout. Il faudrait, en fait.

Je ne suis pas d'humeur à créer plus de session EJBS dans cette application déjà gonflée EJB, mais ce n'est peut-être pas la seule solution à déchirer la CMT dans un tas d'endroits où je préfère ne pas toucher.


4 commentaires

Non je suis confus :). Je peux me tromper mais à mon avis si vous avez un attribut @Required sur le haricot et que vous l'appelez à partir du client qui utilise UserTransaction, la transaction CTX est propagée mais une fois que la méthode renvoie le conteneur est en charge et commet la transaction parce que son CMT haricot. Encore une fois, l'utilisation d'un conteneur CMT commet la transaction comme je l'ai écrite, il n'y a rien d'inhabituel.


Nclark, je suis un peu perplexe par votre note. Peut-être que si vous postez un exemple de code, nous pourrions aider à déchiffrer l'endroit où vous pourriez enfreindre les règles. Cela peut également aider à savoir quel conteneur vous utilisez. En règle générale, si vous utilisez une maîtrise d'utilisateur au mauvais endroit, le conteneur vous donnera des exceptions pour vous.


@John - Je pense que nous devrons peut-être avoir besoin d'une équipe d'avocats pour interpréter la langue utilisée dans les spécifications et ailleurs, mais je référencement le Tutoriels Sun J2ee : Vous ne devez invoquer aucune méthode pouvant interférer avec les limites de transaction définies par le conteneur ...


@Kris - J'ai accepté votre interprétation de cela au début, mais à nouveau relecture de la liste des tutoriels J2EE Verbiage que vous citez ci-dessous, il peut sembler de promettre un commit sur chaque sortie EJB, mais je pense que le mot "typiquement" est vraiment destiné à étendre commettre aussi bien que commencer la transaction. Si vous y réfléchissez, si la commission est-elle toujours arrivée, vous ne pouvez jamais enruser plusieurs EJB dans une transaction parapluie, car le premier commettrait toujours lors de la fin.



22
votes

REQUISE peut être mal

Personnellement, je ne pas comme l'attribut de transaction et REQUISE déconseillons fortement son utilisation.

paresseusement la création de transactions (qui est ce REQUISE fait) les résultats en ne sachant pas vraiment quand et où une opération a été effectivement commencé et quand il engagera. C'est pas une bonne chose. Les gens devraient explicitement concevoir des limites transactionnelles.

et INDISPENSABLE UserTransaction sont accouple âme

Votre désir d'utiliser un UserTransaction est très bon et Finalité travailler avec CMT - il n'y a pas de différence entre une transaction JTA a commencé par UserTransaction fourni par le conteneur ou JTA a commencé pour vous par le conteneur.

L'approche que je recommande est de passer toute utilisation nécessaire pour OBLIGATOIRES . Avec le conteneur OBLIGATOIRES pas lancer des transactions pour vous. Au contraire, il protégera votre haricot en veillant à ce qu'il ne peut pas être appelé à moins qu'une transaction est en cours. Ceci est une caractéristique étonnante et sous-utilisées. INDISPENSABLE est le meilleur ami de tous ceux qui veulent créer une application transactionnelle vraiment déterministe et faire respecter. Avec cette configuration, vous pourriez tomber amoureux de CMT.

Dans ce scénario démarrer les transactions avec UserTransactions et le conteneur est comme votre grand garde du corps des gens coups de pied au bord du trottoir à moins qu'ils aient commencé une opération appropriée avant d'essayer d'invoquer votre code.

Considérations
  • Un Servlet ou un BMT EJB peuvent utiliser un UserTransaction.
  • CMT les haricots ne peuvent pas utiliser un UserTransaction, mais ils peuvent participer à une opération lancée par un UserTransaction (comme indiqué ci-dessus, une transaction JTA est une transaction JTA).
  • BMT les haricots ne peuvent pas participer à une transaction existante. Si vous appelez un haricot BMT alors qu'une transaction est déjà en cours, la transaction sera suspendue par le conteneur avant d'appeler le grain BMT et a repris après la méthode finalise.
  • @Resource UserTransaction vous obtiendrez la transaction utilisateur par injection
  • java: comp / UserTransaction vous obtiendrez la transaction utilisateur via recherche
  • @TransactionAttribute (INDISPENSABLE) utilisé au niveau de la classe aura une incidence sur les méthodes de cette classe exacte (à savoir le fooClass.getDecaredMethods () ). Méthodes de super-classes et sous-classes seront par défaut @TransactionAttribute (OBLIGATOIRE) à moins que ces classes sont explicitement annotées @TransactionAttribute (INDISPENSABLE)
  • Si vous tombez malade d'appeler userTransaction.begin () et userTransaction.commit () et faire la gestion des exceptions connexes, pensez @TransactionAttribute (REQUIRES_NEW) . Vos limites de transaction seront toujours documentées et explicites.
  • RuntimeException s jeté d'une méthode d'un grain de CMT provoquera la transaction à marquer pour rollback, même si vous attraper et gérer l'exception dans le code d'appel. Utilisez @ApplicationException pour désactiver cette option pour un cas par cas pour exécution personnalisée classes d'exception.

    Perdre votre contexte de transaction

    Un couple de choses peuvent causer votre transaction en cours d'arrêt, suspendre ou ne se propage pas à la fève appelée.

    • haricots BMT arrêter la propagation des transactions. Si une transaction en cours appelle un haricot BMT, cette transaction sera suspendue avant que le haricot BMT est appelée et sera repris après le retour du haricot. les haricots BMT peuvent être à l'origine des transactions, mais ne peuvent pas participer à des opérations existantes. Si la propagation est mystérieusement échoué, assurez-vous qu'il n'y a pas d'appels involontaires aux haricots BMT à la mi-transaction.
    • Ne pas utiliser autre chose qu'un UserTransaction conteneur fourni ou conteneur fourni des méthodes telles que SessionContext.setRollbackOnly pour gérer les transactions. L'utilisation d'une "démarcation transaction spécifique au gestionnaire de ressources API" tels que JPA EntityTransaction ou java.sql.Connection.commit () transaction circumvent gestion.
    • Ne commencez pas vos propres fils. la propagation de la transaction se produit sur une base par thread. Il y a pas API standard Java EE qui prennent en charge une transaction couvrant plusieurs threads. Si vous laissez le fil soit de démarrer votre propre fil ou à l'aide @Asynchronous, vous quitterez votre derrière de transaction existante.


7 commentaires

"Les haricots CMT ne peuvent pas utiliser detransaction utilisateur, mais ils peuvent participer à une transaction lancée par une maîtrise d'utilisateur (comme indiqué ci-dessus, une transaction JTA est une transaction JTA)." Le bon sens me dit que cela devrait être vrai, mais ce n'est pas ce que j'observe sous WL 10.3, et je n'ai trouvé aucune déclaration claire à ce sujet dans les spécifications CMT, autres que l'avertissement plutôt vague contre l'utilisation de l'API UserTransaction avec CMT .


Nice post btw. Je suis d'accord avec votre point sur les frontières transactionnelles explicites. Le plus gros problème que j'ai avec cette application Legacy est que la logique de back-end est trop complexe et que les limites de transaction ont été attribuées à la collage aveuglément "requise" sur chaque EJB du système. Le résultat est des dizaines de transactions par demande d'utilisateur!


La spécification est très claire sur elle dans EJB 3.1 Section 13.6.2.2. Quand il est dit "contexte de transaction", cela le signifie avec emphase et sans exception. Il y a des tests dans le Java EE TCK qui passent spécifiquement de l'utilisateurTransaction à un haricot CMT avec obligatoire. Ces tests particuliers sont très anciens et WLS 10.3 les aura réussi. Assurez-vous de ne pas creuser dans des API spécifiques à l'hibernation qui affectent les transactions. Les applications des SPEX explicitement des États ne doivent pas utiliser "API de démarcation de transaction spécifique du gestionnaire de ressources".


Je ne pense pas que nécessaire est ce mal. Il est correct que nous ne pouvons pas nous assurer que nécessaire commencera une nouvelle transaction ou non, car le nécessaire laisse cette décision à l'appelant. Si vous appelez obligatoire sans transaction, cela commencera une nouvelle, sinon, il utilisera l'existence. Ce n'est pas si grave IMHO, il suffit de l'utiliser dans la bonne situation, comme d'autres transactsattributes.


@Davidbleins Great Post, pas sûr de la façon dont j'ai raté jusqu'à présent, éteigné tout de suite, testera dès que possible, quels obligatoires ont à offrir à différents endroits où je pense que cela peut aider. J'ai une question cependant, en ce qui concerne la dernière balle de votre réponse, "Ne démarrez pas vos propres threads". Eh bien, je envisage de commencer mes propres threads dans l'une des intégrations ma société construit pour une application d'entreprise propriétaire. Et la raison est exactement comme vous l'avez dit, de courir sur une transaction séparée. Pourquoi ne puis-je pas utiliser le requérant_new que vous pourriez poser, je l'utilise, même si je dois intégrer mon plugin à l'aide de l'auditeur d'événement ..


@Davidbleins ... Mécanisme de cette application d'entreprise, et il semble qu'il est appelé dans la même transaction où il a été tiré dans la session Bean à l'intérieur de l'application. Le problème est que j'essaie de changer le contenu de la ligne de la table même de cette transaction. Par conséquent, j'obtiens des exceptions en raison d'une violation d'isolement d'instantané ou d'une raison mystérieuse que j'ai encore à découvrir. Ce que j'ai à l'esprit comme une solution, c'est de tirer un fil séparé, laissez-le attendre un peu (donc la transaction existante commises) alors faites mon truc sur la table sur une nouvelle transaction. J'apprécierais votre contribution à ce sujet


@Davidblevins Correction de la faute de frappe dans les mentions ci-dessus



2
votes

Nclark, considérez le code suivant que j'ai couru sur Glassfish 3.1.1. J'espère que cela aidera de quelque manière que ce soit: -) xxx

Cet ejb peut être invoqué, c'est-à-dire à partir de Singleton EJB avec @startup pour voir immédiatement comment votre tel que réagira.

Sur Glassfish 3.1.1, vous arriverez avec le résultat suivant:

Info: #### TestMethod #### TX Statut: 0

Info: #### Testit #### TX Statut: 1

Info: #### TestMethod #### TX Statut: 1

acclamations!


0 commentaires