Bonjour à tous,
J'aimerais vous soumettre un problème qui me pollue l'existence depuis 1 semaine
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 ? ...
Sur un exemple, ça donnerait quelque chose comme ça :
Dans la servlet appelante :
Code :
- try {
- UserTransaction ut = ...
- ut.begin();
- MyProcess mp = new MyProcess();
- mp.step1();
- }
- catch (Exception e) {
- {
- ut.setRollbackOnly();
- }
- finally
- {
- try { ut.commit(); } catch (..) {...}
- }
|
Avec dans la classe MyProcess :
Code :
- void step1(ut);
- {
- Connection con = getConnection();
- try {
- // Insertion de données
- "INSERT INTO T ...
- // D'autres choses qui pourraient lever une exception ...
- ...
- // Log de l'état "ok" du processus
- log("step1", "success" );
- }
- catch (Exception e) {
- log("step1", "failure" );
- throw e;
- }
- finally
- {
- // Fermeture connection, etc...
- }
- }
- void log(String step, String status)
- {
- Connection con = getConnection();
- try {
- // Insertion du status pour le step ...
- "INSERT INTO STATUS (STEP, STATUS) values (?, ?)
- }
- catch (Exception e) {
- // etc ...
- }
- finally
- {
- // Fermeture connection, etc ...
- }
- }
|
Cet exemple est un cas d'école, n'est-ce pas ?
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 ... ??
Merci d'avoir lu jusque là en tout cas !