2010-08-04 4 views
2

Dans une application Web Spring/Hibernate, j'utilise une file d'attente de travail construite avec des threads Java. La méthode run() de Threads appelle une procédure Oracle, qui peut durer plusieurs minutes/heures. Tous les threads de Work Queue sont stockés dans une liste.Arrêt d'un thread Java qui appelle une procédure Oracle

Je voudrais construire une interface (JSP), où je pourrais afficher une liste des travaux en cours, et permettre aux utilisateurs de "tuer" un travail.

Je ne peux pas utiliser la méthode Thread.stop(), qui est obsolète. J'ai également déjà essayé les différentes méthodes avec interrupt(), mais je n'ai pas réussi à arrêter le fil pendant l'appel d'Oracle.

  • Pensez-vous qu'il est possible d'arrêter un thread pendant un appel Oracle?
  • Sinon, devrais-je chercher un autre moyen de faire cette file d'attente de travail (sans threads)?

Merci beaucoup!

Répondre

1

Vous devez appeler Statement.cancel() à partir de l'application Web, sous la forme indicated in this answer on SO. Cela peut ne pas être une bonne implémentation, car l'accès à l'objet Statement doit être rendu disponible sur deux threads au strict minimum, ce qui n'est pas forcément une bonne pratique de programmation.

EDIT: Dans le cas où je ne suis pas assez clair, vous devez stocker des références aux objets Statement qui exécutent les requêtes, et les rendre disponibles aux annuler les opérations (qui exécutera dans différents threads) si les utilisateurs choisissent d'annuler l'exécution des travaux. Si cette approche échoue (généralement en raison d'une supposition incorrecte de la sécurité de thread de l'objet Statement), vous pouvez interrompre le thread exécutant l'instruction et annuler l'exécution de l'instruction à partir du thread d'origine.

0

Le problème est que l'interruption ne signale pas le comportement du pilote Oracles JDBC. À ma connaissance, tuer le thread avec le Thread.stop obsolète() est votre seul moyen, sauf si vous remodelez la solution un peu et même pas cela peut garantir que l'opération dans la base de données réellement arrêté. Il peut toujours être en cours d'exécution à moins que vous l'annuliez en exposant l'instruction à la logique de contrôle des interfaces utilisateur et après avoir supprimé le thread, vous auriez du mal à envoyer la commande ROLLBACK à la base de données.

Mon conseil est soit de le laisser tourner mais signaler au thread qu'il devrait faire un ROLLBACK quand c'est fait.

L'autre est de faire en sorte que votre procédure ne dure pas si longtemps et d'ajouter des étapes intermédiaires qui vous permettent d'arrêter proprement le fil.

2

« dois-je chercher une autre façon de faire cette file d'attente de travail (sans fils) »

Il me semble que vous réinventer la fonctionnalité de travail de base de données Oracle fournit déjà.

Il y a le DBMS_SCHEDULER qui a été introduit dans Oracle 10g, ce qui est plutôt sophistiqué. Dans les versions antérieures, il n'y a que DBMS_JOB, ce qui est encore assez bon: il fera un meilleur travail (ho ho) de l'exécution des procédures stockées en arrière-plan que votre mise en œuvre actuelle.

0

Il s'agit plus d'une sauvegarde d'autres réponses.

Le gros problème que vous aurez est que s'il est possible de tuer le thread Java, le bloc pl/sql peut continuer à s'exécuter sur le serveur quelque temps après. J'ai eu ce problème avec le code C dans le passé et vous pouvez soit essayer d'envoyer un 'cancel' au serveur et attendre qu'il soit reconnu (ce qui ne sera peut-être jamais) ou de 'faire de votre mieux ', terminer le thread en cours de toute façon, et laisser Oracle nettoyer plus tard quand il détecte le processus client a disparu. La réponse des APC est bonne - cela semble être un cas idéal pour le planificateur de tâches en arrière-plan d'Oracle, qui offre une bonne vue sur l'exécution des tâches, et une API pour démarrer/arrêter/etc.

Un petit avantage ici est que vous n'entretenez pas les connexions de votre pool de connexions JDBC avec des transactions à exécution longue. Où je pense que vous pouvez toujours avoir un problème pour arrêter une tâche en cours d'exécution au milieu. La documentation Oracle pour DBMS_JOB indique qu'il n'y a aucun moyen d'arrêter un travail une fois démarré. Une solution que j'ai faite est de vérifier périodiquement que mon travail d'arrière-plan vérifie une condition de 'sortie' (c'est-à-dire qu'une ligne existe dans la table) - mais cela ne fonctionne que si vous avez une boucle.

Questions connexes