2017-07-30 1 views
0

Je rencontre des problèmes de chargement/stockage de données MySQL, ceci est mon codeParfait pour utiliser les données MySQL mise à jour/stockage sans retard et d'erreurs à la mise à jour des statistiques

public void loadPlayer(Player p) { 

if (isPlayerInDataBase(p)) { 

    Bukkit.getScheduler().runTaskAsynchronously(Main.getInstance(), new Runnable() { 
     @Override 
     public void run() { 
      Connection connection = sql.getConnection(); 
      try { 
       PreparedStatement select = connection 
         .prepareStatement("SELECT * FROM `MurderData` WHERE playername='" + p.getName() + "'"); 
       ResultSet result = select.executeQuery(); 

       if (getPlayerData(p) != null) { 
        while (result.next()) { 

         getPlayerData(p).setdeaths(result.getInt("deaths")); 
         getPlayerData(p).setkills(result.getInt("kills")); 
         getPlayerData(p).setwins(result.getInt("wins")); 
         getPlayerData(p).setlose(result.getInt("loses")); 
         getPlayerData(p).setscore(result.getInt("score")); 
         getPlayerData(p).setcoins(result.getInt("coins")); 
        } 

        CloseResultSet(result); 

       } 
      } catch (SQLException e) { 
       e.printStackTrace(); 
      } 

     } 
    }); 
} else { 
    Connection connection = sql.getConnection(); 
    Bukkit.getScheduler().runTaskAsynchronously(Main.getInstance(), new Runnable() { 
     @Override 
     public void run() { 
      try { 
       PreparedStatement insert = connection.prepareStatement(
         "INSERT INTO `MurderData` (playername, wins, deaths, loses, kills, coins, score) VALUES (?, ?, ?, ?, ?, ?, ?)"); 
       insert.setString(1, p.getName()); 
       insert.setInt(2, 0); 
       insert.setInt(3, 0); 
       insert.setInt(4, 0); 
       insert.setInt(5, 0); 
       insert.setInt(6, 0); 
       insert.setInt(7, 0); 
       insert.executeUpdate(); 
       ClosePreparedStatement(insert); 
      } catch (SQLException e) { 
       e.printStackTrace(); 
      } 

     } 

public boolean isPlayerInDataBase(Player p) { 
     Connection connection = sql.getConnection(); 
     try { 
      PreparedStatement select = connection 
        .prepareStatement("SELECT * FROM `MurderData` WHERE playername='" + p.getName() + "'"); 
      ResultSet result = select.executeQuery(); 
      if (result.next()) { 
       CloseResultSet(result); 
       return true; 
      } 
     } catch (SQLException e) { 
      e.printStackTrace(); 
     } 
     return false; 
    } 

La question est donc essentiellement, devrais-je fermer les instructions préparées après la mise à jour des données MySQL? et devrais-je faire cela avoir un retard comme le fermer après 5 secondes? puis-je optimiser ce code pour le rendre meilleur?

Le joueur est dans la base de données, n'est-ce pas?

ceci est mon 2 méthodes de fermeture:

public void CloseResultSet(ResultSet s) { 

     new BukkitRunnable() { 

      @Override 
      public void run() { 

       if (s != null) { 
        try { 
         s.close(); 
        } catch (SQLException e) { 
         // TODO Auto-generated catch block 
         e.printStackTrace(); 
        } 
       } 

      } 
     }.runTaskLater(this, 20 * getConfig().getInt("close-sql-statements-after")); 
    } 

    public void ClosePreparedStatement(PreparedStatement s) { 

     new BukkitRunnable() { 

      @Override 
      public void run() { 

       if (s != null) { 
        try { 
         s.close(); 
        } catch (SQLException e) { 
         // TODO Auto-generated catch block 
         e.printStackTrace(); 
        } 
       } 

      } 
     }.runTaskLater(this, 20 * getConfig().getInt("close-sql-statements-after")); 

    } 

Mise à jour: il est le deuxième problème, le premier problème est les petites pointes de lag deuxième problème est le stockage de données en ligne 252

public void setSQLData(Player p, int kills, int deaths, int loses, int wins, int coins, int score) { 
     Bukkit.getScheduler().runTaskAsynchronously(plugin, new Runnable() { 
      @Override 
      public void run() { 
       Connection connection = plugin.sql.getConnection(); 
       try { 
        PreparedStatement insert = connection.prepareStatement(
          "INSERT INTO `MurderData` (playername, wins, deaths, loses, kills, coins, score) VALUES (?, ?, ?, ?, ?, ?, ?)"); 
        insert.setString(1, p.getName()); 
        insert.setInt(2, wins); 
        insert.setInt(3, deaths); 
        insert.setInt(4, loses); 
        insert.setInt(5, kills); 
        insert.setInt(6, coins); 
        insert.setInt(7, score); 
        insert.executeUpdate();// error line 252 
        plugin.ClosePreparedStatement(insert); 
       } catch (SQLException e) { 
        e.printStackTrace(); 
       } 

      } 

     }); 
    } 

    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) 
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source) 
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source) 
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at java.lang.reflect.Constructor.newInstance(Unknown Source) 
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at com.mysql.jdbc.Util.handleNewInstance(Util.java:407) 
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:1116) 
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3082) 
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:2968) 
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3516) 
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1986) 
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2140) 
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2626) 
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2111) 
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2407) 
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2325) 
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2310) 
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at me.joseph.murder.api.MurderAPI$1.run(MurderAPI.java:252) 
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at org.bukkit.craftbukkit.v1_8_R3.scheduler.CraftTask.run(CraftTask.java:71) 
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at org.bukkit.craftbukkit.v1_8_R3.scheduler.CraftAsyncTask.run(CraftAsyncTask.java:53) 
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) 
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) 
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at java.lang.Thread.run(Unknown Source) 
[22:31:18] [Craft Scheduler Thread - 71/WARN]: Caused by: java.io.EOFException: Can not read response from server. Expected to read 4 bytes, read 0 bytes before connection was unexpectedly lost. 
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at com.mysql.jdbc.MysqlIO.readFully(MysqlIO.java:2529) 
[22:31:18] [Craft Scheduler Thread - 71/WARN]: at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:2979) 
+2

Au lieu de fonctionner de cette façon, syncronously avec fil conducteur de Bukkit, exécutez dans un fil asynchrone, ce qui en fait le fond. Il ne devrait pas verrouiller votre serveur, ne causant ainsi pas de retard – Kerooker

+1

De même, exécuter une requête dans 'isPlayerInDataBase (Player p)', puis réexécuter exactement la même requête s'il est dans la base de données semble un peu redondant. Utilisez simplement les données que vous avez obtenues lors de la vérification. – Solarflare

+1

Cela pourrait être complètement hors base, mais une autre façon (en dehors des deux mentionnés par Kerooker et Solarflare) pour aider le lag est (avec des ressources système permettant) de mettre en cache les joueurs récents qui partent, donc s'ils reviennent bientôt vous n'avez plus besoin de récupérer leurs données. Maintenant, cela ne ferait que rendre les choses plus rapides si vous avez les ressources du système le permettent, et si ce n'est pas le cas, cela pourrait ralentir les choses. Maintenant, la mise en cache est une pratique courante. Cependant, je ne sais pas à quel point cela est vrai pour mysql ou bukkit/minecraft. –

Répondre

1

d'abord all:

Pour autant que je puisse voir, vous fermez la connexion chaque fois que vous exécutez une requête/mise à jour. Ceci est malheureusement très imparfait. Il serait préférable d'ouvrir une connexion MySQL lorsque le plugin démarre et de le refermer lorsque le plugin s'arrête.

Personnellement, je fait cette façon: (Ne signifie pas que vous devez le faire de cette façon)

La variable de connexion:

private static Connection connection; 

La fonction de connexion:

public static void connect(String host, String user, String password, String database) { 
    Bukkit.getScheduler().runTaskAsynchronously(Main.getInstance(),() -> { 

     //close Connection if still active 
     if (connection != null) { 
      close(); 
     } 

     //connect to database host 
     try { 
      Class.forName("com.mysql.jdbc.Driver"); 

      connection = DriverManager.getConnection("jdbc:mysql://" + host + "/" + database, user, password); 

     } catch (SQLException e) { 
      System.out.println(e.getMessage()); 
     } 

    }); 
} 

Ma fonction pour mettre à jour/écrire des entrées dans la base de données:

public void Update(final String qry) { 
    Bukkit.getScheduler().runTaskAsynchronously(Main.getInstance(),() -> { 
     try { 
      Statement stnt = connection.createStatement(); 
      stnt.executeUpdate(qry); 

     } catch (SQLException e) { 
      e.printStackTrace(); 
     } 
    }); 

} 

Ma fonction pour interroger les informations de la base de données:

Comme vous pouvez le voir, cette fonction n'est pas asynchrone. Je n'ai malheureusement pas réussi à obtenir cette fonction asynchrone. Mais vous pouvez facilement contourner ce problème en rendant l'appel de fonction asynchrone. ex: Bukkit.getScheduler().runTaskAsynchronously(Main.getInstance(),() -> { Query("your query"); });

public ResultSet Query(String qry) { 
    ResultSet rs = null; 

    try { 
     Statement stnt = connection.createStatement(); 
     rs = stnt.executeQuery(qry); 
    } catch (SQLException e) { 
     e.printStackTrace(); 
    } 
    return rs; 
} 

La fonction proche:

public static void close() { 
    Bukkit.getScheduler().runTaskAsynchronously(Main.getInstance(),() -> { 
     try { 
      connection.close(); 
     } catch (SQLException e) { 
      System.out.println(e.getMessage()); 
     } 
    }); 
} 

Un inconvénient de cette façon est que vous ne pouvez vous connecter à une base de données à la fois (ce qui était dans mon cas très bien).

J'espère que cela vous aide. J'ai aussi beaucoup lutté avec des erreurs MySQL bizarres. Heureusement avec ce code tout fonctionne très bien.

Pour répondre à votre question:

[22:31:18] [Craft Scheduler Thread - 71/WARN]: Caused by: java.io.EOFException: Can not read response from server. Expected to read 4 bytes, read 0 bytes before connection was unexpectedly lost. 

Pour autant que je sais que cela signifie que la connexion au serveur MySQL est fermé, même si le plugin essaie de l'utiliser. Comme mentionné ci-dessus, ouvrir une connexion au démarrage et la laisser ouverte jusqu'à ce que les arrêts du plugin le résolvent.

0

Merci pour tous ceux qui ont j'ai pensé que le problème était sur cette ligne

public void setSQLData(Player p, int kills, int deaths, int loses, int wins, int coins, int score) { 


    Bukkit.getScheduler().runTaskAsynchronously(plugin, new Runnable() { 
     @Override 
     public void run() { 
      Connection connection = plugin.sql.getConnection(); 
      try { 
       PreparedStatement insert = connection.prepareStatement(
         "INSERT INTO `MurderData` (playername, wins, deaths, loses, kills, coins, score) VALUES (?, ?, ?, ?, ?, ?, ?)"); 

il devrait être mise à jour n'insérer