2017-10-02 3 views
0

J'essaye d'apprendre des discussions et des tâches pendant des jours maintenant ... mais ne peux toujours pas l'implémenter dans mon application ... aidez svp.JavaFX Pourquoi la tâche renvoie Null?

Je souhaite exécuter toutes les opérations de base de données dans un thread d'arrière-plan autre que le thread d'application. J'ai une classe qui gère les requêtes de base de données ... dans cette classe i entouré la déclaration executeQuery une tâche:

public class Database { 

ResultSet rs; 

public ResultSet execQuery(PreparedStatement stmnt) throws SQLException {  
    Task<ResultSet> task = new Task<ResultSet>() { 
    @Override protected ResultSet call() throws Exception { 
      if (isCancelled()) { 
      }      

       ResultSet execRs = stmnt.executeQuery(); 
       return execRs; 
     } 
    };  
    task.run(); 
    task.setOnSucceeded(new EventHandler<WorkerStateEvent>(){ 
     @Override 
     public void handle(WorkerStateEvent event) {     
      rs = task.getValue(); 
     }    
    }); 
    return rs; 
} 
// remaining Code 
} 

Comme vous pouvez le voir la méthode doit retourner un ResultSet mais quand je l'appelle depuis un autre lieu il soulève un pointeur nul ... l'ensemble de résultats retourné par cette méthode est null.

Alors qu'est-ce que je fais mal ici?

Mise à jour # 1 @James_D Merci pour ce grand link ... Je pense que je comprends enfin le concept ... mais qui ont encore un petit problème avec sa mise en œuvre ... par exemple dans ma méthode d'authentification après l'utilisateur est authentifié je veux vérifier si cet utilisateur a un changement ouvert ... donc suivant votre lien j'ai changé la méthode à ceci:

private boolean isShiftOpen(int userId, int branchId, int comId) throws SQLException, ClassNotFoundException { 
//  final boolean success = false; 
     Task<Shift> task = new Task<Shift>(){ 
      @Override 
      protected Shift call() throws Exception { 
       return ShiftDAO.getShift(userId, branchId, comId); 
      }    
     }; 
     task.setOnFailed(e -> { 
      System.out.println("isShiftOpenTask Faild!!"); 
      success = false; 
     }); 
     task.setOnSucceeded(e -> { 
      System.out.println("isShiftOpenTask Succeeded!!"); 
      Shift shift1 = task.getValue(); 
      System.out.println("User Open Shift Exists ... returning true"); 
      SessionBean.setShiftId(shift1.getShiftId()); 
      SessionBean.setUserId(shift1.getUserId()); 
      SessionBean.setUserBranch(branchId); 
      success = true; 
     }); 
     exec.execute(task); 
     return success; 

    } 

J'ai deux problèmes: 1- la exec.execute (tâche) déclenche une exception nullpoint. 2- Je voulais utiliser une variable booléenne renvoyée par cette méthode ... la seule façon d'accéder à une telle variable est de la définir en dehors de la méthode ... mais si je veux utiliser une autre méthode comme celle-ci je dois déclarez une autre variable booléenne pour cela ... cela vous semble-t-il correct?

Merci pour votre temps Gado

+0

Le problème 1. n'est pas apparenté; vous pouvez facilement déboguer le NPE, voir https://stackoverflow.com/questions/218384/what-is-a-nullpointerexception-and-how-do-i-fix-it. Pour 2., encore une fois, si vous exécutez ceci sur un thread d'arrière-plan, la méthode 'isShiftOpen' retournera * avant * que la tâche soit terminée. C'est essentiellement le point d'utiliser un thread. Vous ne pouvez donc pas renvoyer une valeur qui dépend de ce qui se passe dans la tâche. Qu'allez-vous faire avec cette valeur?Quoi qu'il en soit, cela devrait aller dans les gestionnaires onSucceeded et onFailed. –

Répondre

2

Vous appelez

task.run(); 

qui exécute la tâche sur le thread courant, à savoir que la déclaration ne sera pas complète tant que la fin de tâche. Alors vous appelez

task.setOnSucceeded(...); 

qui dit essentiellement « lorsque la tâche réussit, définissez la variable d'instance rs au résultat de la tâche. Cependant, au moment où vous appelez cela, la tâche a déjà réussi (ou peut-être n'a pas), donc il n'y a aucun moyen pour le gestionnaire à invoquer.

vous pouvez fixer le résultat nul en inversant l'ordre de ces appels, à savoir faire

public ResultSet execQuery(PreparedStatement stmnt) throws SQLException {  
    Task<ResultSet> task = new Task<ResultSet>() { 
    @Override protected ResultSet call() throws Exception { 
      if (isCancelled()) { 
      }      

       ResultSet execRs = stmnt.executeQuery(); 
       return execRs; 
     } 
    };  
    task.setOnSucceeded(new EventHandler<WorkerStateEvent>(){ 
     @Override 
     public void handle(WorkerStateEvent event) {     
      rs = task.getValue(); 
     }    
    }); 
    task.run(); 
    return rs; 
} 

Cependant, puisque vous êtes ex En écrivant la tâche sur le thread actuel, il n'est pas vraiment clair à quoi sert une tâche: vous pouvez aussi simplement exécuter la requête de la base de données directement dans votre méthode execQuery et renvoyer le résultat directement. En d'autres termes, le code ci-dessus est équivalent à

public ResultSet execQuery(PreparedStatement stmnt) throws SQLException {  

    rs = stmnt.executeQuery(); 
    return rs; 

} 
+0

Merci pour la réponse ... D'abord j'ai essayé votre suggestion pour appeler le run() après le setOnSucceeded() mais retourne toujours null. Deuxièmement, mon intention n'est pas d'exécuter ce sur le même thread que je veux l'exécuter sur un thread séparé. (Mise à jour de la question) – Gado

+0

@Gado Vous devez vous assurer qu'il ne lève pas une exception. Par exemple. faire 'task.setOnFailed (event -> tâche.getException(). printStackTrace());' (avant d'appeler 'run()', évidemment). Si vous voulez le faire dans un thread d'arrière-plan, cependant, il sera * impossible * de renvoyer le jeu de résultats à partir de la méthode 'execQuery()', car cette méthode quittera probablement * avant que la requête de la base de données soit terminée. Vous avez probablement besoin de repenser entièrement la conception ici, si vous voulez exécuter la requête dans un thread d'arrière-plan. –

+0

@Gado Jetez un oeil à https://stackoverflow.com/questions/30249493/using-threads-to-make-database-requests –