2010-05-26 6 views
0

Je suis relativement nouveau avec hiberner alors s'il vous plaît soyez doux. Je rencontre un problème avec une méthode longue durée (~ 2 min de long) et la modification de la valeur d'un champ d'état sur un objet stocké dans la base de données. Le pseudo-code ci-dessous devrait aider à expliquer mon problème.Longue méthode de fonctionnement causant l'état de la course

public foo(thing) { 
    if (thing.getStatus() == "ready") { 
     thing.setStatus("finished"); 
     doSomethingAndTakeALongTime(); 
    } else { 
     // Thing already has a status of finished. Send the user back a message. 
    } 
} 

Le pseudo-code ne devrait pas prendre beaucoup d'explications. Je veux que doSomethingAndTakeALongTime() s'exécute, mais seulement s'il a un statut "prêt". Mon problème se pose chaque fois que cela prend 2 minutes pour que doSomethingAndTakeALongTime() se termine et que la modification du champ d'état de l'objet ne soit pas conservée dans la base de données tant qu'elle n'a pas quitté foo(). Ainsi, un autre utilisateur peut faire une demande pendant ces 2 minutes et l'instruction if sera évaluée à true.

J'ai déjà essayé de mettre à jour le champ et le rinçage de la session manuellement, mais il ne semble pas fonctionner. Je ne sais pas quoi faire d'ici et j'apprécierais toute aide.

PS: Ma session de mise en veille prolongée est géré par ressort.

+2

Pour éviter les failles rouges: vous savez que vous devez comparer les chaînes en utilisant 'equals()'? – BalusC

+1

Votre méthode est-elle dans un contexte de transaction, par ex. printemps des transactions déclaratives? Si c'est le cas, le rinçage n'aidera pas puisque les autres utilisateurs ne verront pas la modification. – mdma

+0

@BalusC, oui j'en suis conscient. Mon code réel n'utilise pas de chaîne; Je viens de créer cet exemple, et incorrectement, pour votre plus grand plaisir. :) – keeleyt83

Répondre

2

Fondamentalement, vous devez le laisser tourner dans un Thread séparé pour rendre la méthode de revenir immédiatement. Sinon, il bloquera en effet jusqu'à ce que la tâche de longue durée soit terminée. Vous pouvez passer l'entité elle-même au thread, afin qu'elle puisse mettre à jour le statut lui-même. Voici un exemple de coup d'envoi de base en utilisant un simple Thread.

public class Task extends Thread { 
    private Entity entity; 
    public Task(Entity entity) { 
     this.entity = entity; 
    } 
    public void run() { 
     entity.setStatus(Status.RUNNING); 
     // ... 
     // Long running task here. 
     // ... 
     entity.setStatus(Status.FINISHED); 
    } 
} 

et

public synchronized void foo(Entity entity) { 
    if (entity.getStatus() == Status.READY) { 
     new Task(entity).start(); 
    } else { 
     // ... 
    } 
} 

Avec le Status dans un enum vous pouvez même utiliser une instruction switch au lieu d'un if/else.

switch (entity.getStatus()) { 
     case READY: 
      new Task(entity).start(); 
      break; 
     case RUNNING: 
      // It is still running .. Have patience! 
      break; 
     case FINISHED: 
      // It is finished! 
      break; 
    }    

Pour un contrôle plus robuste de threads en cours d'exécution, vous pouvez envisager ExecutorService à la place. Vous pouvez ainsi contrôler le nombre maximum de threads et spécifier un délai d'expiration.

+0

Hmm ... J'ai essayé de faire synchroniser foo() plus tôt aujourd'hui et ça n'a pas l'air de marcher. Tout ce que j'ai fait, c'était ajouter le modificateur "synchronized".Y a-t-il autre chose à faire pour en faire une méthode synchronisée? – keeleyt83

+0

"synchronized" n'aidera que si vous faites l'autre travail lié à Thread dont a parlé BalusC. As-tu fais ça? –

+0

@keeley: le modificateur 'synchronized' est juste là pour éviter que d'autres threads entrent dans la méthode alors que l'état doit encore être réglé sur' RUNNING' (et vous risquez donc d'exécuter la tâche longue en cours d'exécution deux fois ou plus). Il ne laisse pas la méthode revenir immédiatement. Faire la tâche longue dans un autre thread permettra à la méthode de retourner immédiatement. Est-ce que tu l'as essayé? – BalusC

0

Qu'est-ce que la méthode doSomethingAndTakeALongTime() fait? est-ce pour l'opération de DB ou exécutant juste une certaine logique d'affaires?

Si son fait aucune opération de DB, et vous avez obtenu votre status bien alors vous pouvez persister l'objet avant d'appeler cette méthode.

Et si son fait une opération DB, alors vous devez attendre. Donc, même si vous mettez dans le fil, vous devez attendre que ce thread se termine (en utilisant thread.join() nous pouvons le faire)

le fait est que, avant de persister, vous devez avoir terminé toutes les opérations en fonction de votre objet ORM droit? Essayez donc d'optimiser la logique de la méthode pour l'exécuter avant de persister.

merci.

Questions connexes