[JTA] "Sous-transaction" depuis une Servlet ...

"Sous-transaction" depuis une Servlet ... [JTA] - Java - Programmation

Marsh Posté le 31-01-2004 à 11:55:35    

Bonjour à tous,
 
J'aimerais vous soumettre un problème qui me pollue l'existence depuis 1 semaine  :fou:  
En synthèse, j'aimerais pouvoir démarrer une sous-transaction JDBC dans une transaction JTA (locale ou globale ça importe peu), afin de commiter seulement une "partie" de mes appels au SGBD, et ceci depuis une servlet. Et surtout sans passer par un EJB (cf attributs required_new sur les méthodes qui me permettraient de faire ça facilement ...)
Un exemple simple de ce que ça permettrait de faire est de logger en base des états "success" ou "failure" de partie de processus qui font des insert, update ou delete dans la base...
Suis-je vraiment clair ? ...  :heink:  
Sur un exemple, ça donnerait quelque chose comme ça :
Dans la servlet appelante :

Code :
  1. try {
  2.     UserTransaction ut = ...
  3.     ut.begin();
  4.     MyProcess mp = new MyProcess();
  5.     mp.step1();
  6.     }
  7. catch (Exception e) {
  8.     {
  9.     ut.setRollbackOnly();
  10.     }
  11. finally
  12.     {
  13.     try { ut.commit(); } catch (..) {...}
  14.     }


 
Avec dans la classe MyProcess :

Code :
  1. void step1(ut);
  2. {
  3.    Connection con = getConnection();
  4.    try {
  5.        // Insertion de données  
  6.        "INSERT INTO T ...
  7.        // D'autres choses qui pourraient lever une exception ...
  8.        ...
  9.        // Log de l'état "ok" du processus
  10.        log("step1", "success" );
  11.        }
  12.     catch (Exception e) {
  13.        log("step1", "failure" );
  14.        throw e;
  15.        }
  16.     finally
  17.        {
  18.        // Fermeture connection, etc...
  19.        }
  20. }
  21. void log(String step, String status)
  22. {
  23.    Connection con = getConnection();
  24.    try {
  25.        // Insertion du status pour le step ...
  26.        "INSERT INTO STATUS (STEP, STATUS) values (?, ?)
  27.        }
  28.     catch (Exception e) {
  29.        // etc ...
  30.        }
  31.     finally
  32.        {
  33.        // Fermeture connection, etc ...
  34.        }
  35. }


 
Cet exemple est un cas d'école, n'est-ce pas ?  :D  
Il pourrait être "résolu" facilement en stockant les messages "loggés" dans une quelconque variable, et en effectuant les insertions en base à la fin de l'exécution de la servlet (donc après le ut.commit()). Mon problème réel est plus générique que ça, et même si j'ai indiqué au début que je ne *voulais* pas utiliser d'EJB, les fonctions dont je parle doivent être utilisables dans n'importe quel contexte (y compris dans ce cas d'EJB...) et sans demander de réécriture de code, ou adaptation du code existant. En gros, ce dont j'ai besoin, c'est d'un OutputStream sur JDBC ;-) (Pas taper, je sais que j'écris une horreur ....)
 
J'ai déjà exploré les pistes suivantes :
1) Utiliser une autre dataSource : pas de chance, elle est incluse d'office dans la transaction JTA démarrée ...
2) Obtenir la connection depuis le DriverManager, et faire un commit JDBC : idem, j'ai une exception qui m'indique que je ne peux pas commiter une transaction JDBC dans une transaction JTA... Normal ...
3) Jouer avec les méthodes susped, begin, etc... et resume du TransactionManager : Déjà c'est pas "standard" (merci Hibernate  :) pour le moyen d'avoir une instance de TransactionManager). Ensuite, même si ça fonctionne sur mon poste de dév (WSAD, MySQL ou Cloudscape) ou un Websphere sur NT, ben ça m'explose férocement à la figure si j'esssaye ça sur ma plate-forme de prod (WS 4 sur un Mainframe sous z/OS) avec des "SecurityException" ... Donc pas moyen d'utiliser cette méthode non plus ...
4) Utiliser un Thread spécifique lancé à partir d'une servlet d'init qui ferait les accès BD (je sais, je sais ... "Normalement" c'est interdit de faire de nouveaux Threads à la main, mais bon ...) : marche pô non plus, cf impossible d'avoir une Connection sur le Mf à partir d'un Thread "anonyme", toujours à cause de JAAS ...
 
Là je craque ...
J'ai été regarder log4j et les différentes versions de JDBCAppender (histoire de voir ce qu'ils avaient fait), mais aucune ne prend ce problème en compte (et donc il peut y avoir des "rollbacks" de logs, ce qui est quand même un comble ...). Je dirai même plus (...) : personne ne semble avoir "détecté" ce problème ... ?
Heelp please ... Est-ce que j'essaye de faire un truc *vraiment* impossible ... ??  :pt1cable:  
Merci d'avoir lu jusque là en tout cas ! :D  
 

Reply

Marsh Posté le 31-01-2004 à 11:55:35   

Reply

Marsh Posté le 31-01-2004 à 12:42:47    

bin session bean et requiresnew. Si tu bosses avec JTA, t'as pas 36 solutions hein. Si tu ne peux pas utiliser de SB, bin je vois mal comment tu peux t'en sortir

Reply

Marsh Posté le 31-01-2004 à 13:01:20    

DarkLord a écrit :

bin je vois mal comment tu peux t'en sortir


en faisant ce que fait le conteneur ejb avec les sb


---------------
ma vie, mon oeuvre - HomePlayer
Reply

Marsh Posté le 31-01-2004 à 13:03:15    

Merci de ta réponse DarkLord.
Après avoir exploré ttes les pistes que j'ai donné en haut, j'en étais à la même conclusion ... mais on a tjrs un peu d'espoir d'avoir raté quelque chose nan ? :)
Maintenant, je trouve qu'il manque qque chose de "standard" dans l'API JTA pour pouvoir faire l'équivalent d'un SB/Requiresnew depuis un container Web sans passer par un EJB ... Y'a tout ce qu'il faut (cf TransactionManager) mais c'est "réservé" au container EJB ...

Reply

Marsh Posté le 31-01-2004 à 13:07:58    

Benou,
 
Je suis d'accord avec toi, c'est d'ailleurs ce que j'ai essayé de faire mais malheureusement ça ne colle pas avec mon env de prod.
En gros le truc c'est :
 

Code :
  1. TransactionManager txMgr = getTxManager(); // Là ça dépend du serveur ...
  2. // On récupère la transaction courante
  3. Transaction currentTx = txMgr.suspend();
  4. // On en démarre une nouvelle
  5. txMgr.begin();
  6. // On peut faire des accès aux ressources
  7. // Commit de la nouvelle tx
  8. txMgr.commit();
  9. // Et restore de l'ancienne
  10. txMgr.resume(currentTx);


 
Le pb comme je l'ai dit plus haut c'est que sur WS z/OS j'ai une SecurityException sur le commit ...

Reply

Marsh Posté le 31-01-2004 à 13:46:02    

désolé, je vais pas pouvoir t'aider : je connais pas JTA :/


---------------
ma vie, mon oeuvre - HomePlayer
Reply

Marsh Posté le 31-01-2004 à 14:14:07    

Benou,
 
Juste pour info, je peux te dire que ce n'est pas sorcier et que si tu codes des SB, EB & co ben tu l'utilises sans le savoir (mode donneur de leçons off of course hein ! :ange: ).  
Y'a 2 trucs à connaitre en fait pour l'utiliser explicitement :
1) Depuis une servlet :  
 UserTransaction ut = (UserTransaction)context.lookup("java:comp/UserTransaction" );
2) Depuis un SB BMP :
 UserTransaction = getContext().getUserTransaction();
Ensuite ut.begin(), ut.commit(), ut.rollback() ou ut.setRollbackOnly().
Bon d'accord... Y'a aussi des subtilités quand tu combines des ressources XA et pas XA, mais en général y'a un architecte qui est passé avant toi pour vérifier que les ressources se coordonnaient correctement ...
Le problème (et c'est pour ça que j'ai parlé de "lacune" dans cette API) c'est qu'elle est partiellement masquée, cf l'interface TransactionManager et le fait qu'il n'y a pas de "méthode" pour récupérer le TransactionManager courant... Si tu as l'occasion, va jeter un oeil au code du projet Hibernate (cf ci-dessus), c'est affligeant de voir comment tout ça peut dériver en choses "non standards" parce que la norme n'est pas assez précise ou complète sur le sujet ...
M'enfin ... Je ne me sens pas trop le courage d'aller poster un truc chez Sun pour leur demander de faire le nécessaire :D . Y z'ont certainement eu une bonne raison pour avoir limité son usage !
 
Au final, je vais logger dans un fichier moua :D
Merci d'avoir pris du temps pour me répondre en tout cas !

Reply

Marsh Posté le 01-02-2004 à 10:32:40    

benou a écrit :


en faisant ce que fait le conteneur ejb avec les sb


 
[:kiki] tu me prends pour un con ou quoi?

Reply

Marsh Posté le 01-02-2004 à 10:33:45    

Ygrec a écrit :

Benou,
 
Juste pour info, je peux te dire que ce n'est pas sorcier et que si tu codes des SB, EB & co ben tu l'utilises sans le savoir (mode donneur de leçons off of course hein ! :ange: ).  
Y'a 2 trucs à connaitre en fait pour l'utiliser explicitement :
1) Depuis une servlet :  
 UserTransaction ut = (UserTransaction)context.lookup("java:comp/UserTransaction" );
2) Depuis un SB BMP :
 UserTransaction = getContext().getUserTransaction();
Ensuite ut.begin(), ut.commit(), ut.rollback() ou ut.setRollbackOnly().
Bon d'accord... Y'a aussi des subtilités quand tu combines des ressources XA et pas XA, mais en général y'a un architecte qui est passé avant toi pour vérifier que les ressources se coordonnaient correctement ...
Le problème (et c'est pour ça que j'ai parlé de "lacune" dans cette API) c'est qu'elle est partiellement masquée, cf l'interface TransactionManager et le fait qu'il n'y a pas de "méthode" pour récupérer le TransactionManager courant... Si tu as l'occasion, va jeter un oeil au code du projet Hibernate (cf ci-dessus), c'est affligeant de voir comment tout ça peut dériver en choses "non standards" parce que la norme n'est pas assez précise ou complète sur le sujet ...
M'enfin ... Je ne me sens pas trop le courage d'aller poster un truc chez Sun pour leur demander de faire le nécessaire :D . Y z'ont certainement eu une bonne raison pour avoir limité son usage !
 
Au final, je vais logger dans un fichier moua :D
Merci d'avoir pris du temps pour me répondre en tout cas !


 
:jap:
 
et je ne connaissais pas le coup du UserTransaction ut = (UserTransaction)context.lookup("java:comp/UserTransaction" ); (faut dire que je suis nul en servlet/JSP aussi)

Reply

Marsh Posté le 01-02-2004 à 11:00:04    

DarkLord a écrit :


[:kiki] tu me prends pour un con ou quoi?


mais nan :o
 

DarkLord a écrit :


et je ne connaissais pas le coup du UserTransaction ut = (UserTransaction)context.lookup("java:comp/UserTransaction" ); (faut dire que je suis nul en servlet/JSP aussi)


rien à voir avec les servlets [:kiki]
 

DarkLord a écrit :


[:kiki] tu me prends pour un con ou quoi?


bha du coup oui un peu [:joce]


---------------
ma vie, mon oeuvre - HomePlayer
Reply

Marsh Posté le 01-02-2004 à 11:00:04   

Reply

Marsh Posté le 01-02-2004 à 11:09:18    

Citation :


UserTransaction ut = (UserTransaction)context.lookup("java:comp/UserTransaction" );  
 
rien à voir avec les servlets [:kiki]


 
Euh ...  
Sans vouloir polémiquer  :ange: je suis d'accord, parce que c'est plutôt une API JTA ...  
Edit : en fait non ... Mais c'est le moyen de récupérer une UT depuis le contexte JNDI
Mais je ne connais pas d'autre endroit où on l'utilise comme ça ?  
Benou > y'en a d'autres ??


Message édité par Ygrec le 01-02-2004 à 11:10:55
Reply

Marsh Posté le 01-02-2004 à 11:28:57    

Ygrec a écrit :

[quote]
Benou > y'en a d'autres ??


j'en sais rien, en tout cas, le lookup a rien à voir avec l'API servlet [:spamafote]


---------------
ma vie, mon oeuvre - HomePlayer
Reply

Marsh Posté le 01-02-2004 à 12:48:45    

benou a écrit :


j'en sais rien, en tout cas, le lookup a rien à voir avec l'API servlet [:spamafote]


 
mais j'ai jamais dit ca.
 
dans un container EJB tu as accès à ta transaction via le SessionContext. Et donc comme je n'ai jamais eu à utiliser je jndi.lookup(...) je ne connaissais pas.
 
maintenant j'en déduis qu'on utilise ce genre de choses princialement en servlet puisque pour tout ce qui est EJB on y accède autrement d'où mon "(faut dire que je suis nul en servlet/JSP aussi)".
 
Et donc réflexion faite, benou, tu me prends *vraiment* pour un con.


Message édité par darklord le 01-02-2004 à 12:53:40
Reply

Marsh Posté le 01-02-2004 à 18:07:18    

DarkLord a écrit :


Et donc réflexion faite, benou, tu me prends *vraiment* pour un con.


t'as fini oui :o
 
 
perso, en servlet, je ne me suis jamais servi de JNDI ... Tomcat le fait un peu, mais généralement les moteurs de servlets simples (pas un websphere ou un weblogic quoi) ne fournissent pas grand chose comme composant => je les instancie moi-même et les range dans le ServletContext ... y a pas vraiment besoin de plus ...


---------------
ma vie, mon oeuvre - HomePlayer
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed