MySQL Abfragen einfach asynchron im Hintergrund

Hier könnt ihr anderen Leuten helfen, indem ihr Anleitungen oder praktische Codesegmente zur Verfügung stellt.

MySQL Abfragen einfach asynchron im Hintergrund

Beitragvon Jofkos » Sa 29. Nov 2014, 23:55

Ich habe zusammen mit @IK_Raptor eine asynchrone MySQL-Klasse in Java 8 geschrieben, hier ist sie: (Alternativ Link)
Code: Alles auswählen
  1. import java.sql.Connection;
  2. import java.sql.DriverManager;
  3. import java.sql.PreparedStatement;
  4. import java.sql.ResultSet;
  5. import java.sql.SQLException;
  6. import java.util.concurrent.ExecutorService;
  7. import java.util.concurrent.Executors;
  8. import java.util.function.Consumer;
  9. import org.bukkit.Bukkit;
  10. import org.bukkit.plugin.Plugin;
  11. public class AsyncMySQL {
  12.    private ExecutorService executor;
  13.    private Plugin plugin;
  14.    private MySQL sql;
  15.    public AsyncMySQL(Plugin owner, String host, int port, String user, String password, String database) {
  16.       try {
  17.          sql = new MySQL(host, port, user, password, database);
  18.          executor = Executors.newCachedThreadPool();
  19.          plugin = owner;
  20.       } catch (Exception e) {
  21.          e.printStackTrace();
  22.       }
  23.    }
  24.    
  25.    public void update(PreparedStatement statement) {
  26.       executor.execute(() -> sql.queryUpdate(statement));
  27.    }
  28.    public void update(String statement) {
  29.       executor.execute(() -> sql.queryUpdate(statement));
  30.    }
  31.    
  32.    public void query(PreparedStatement statement, Consumer<ResultSet> consumer) {
  33.       executor.execute(() -> {
  34.          ResultSet result = sql.query(statement);
  35.          Bukkit.getScheduler().runTask(plugin, () -> consumer.accept(result));
  36.       });
  37.    }
  38.    
  39.    public void query(String statement, Consumer<ResultSet> consumer) {
  40.       executor.execute(() -> {
  41.          ResultSet result = sql.query(statement);
  42.          Bukkit.getScheduler().runTask(plugin, () -> consumer.accept(result));
  43.       });
  44.    }
  45.    
  46.    public PreparedStatement prepare(String query) {
  47.       try {
  48.          return sql.getConnection().prepareStatement(query);
  49.       } catch (Exception e) {
  50.          e.printStackTrace();
  51.       }
  52.       return null;
  53.    }
  54.    
  55.    public MySQL getMySQL() {
  56.       return sql;
  57.    }
  58.    
  59.    public static class MySQL {
  60.       
  61.       private String host, user, password, database;
  62.       private int port;
  63.       
  64.       private Connection conn;
  65.       
  66.       public MySQL(String host, int port, String user, String password, String database) throws Exception {
  67.          this.host = host;
  68.          this.port = port;
  69.          this.user = user;
  70.          this.password = password;
  71.          this.database = database;
  72.          
  73.          this.openConnection();
  74.       }
  75.       
  76.       public void queryUpdate(String query) {
  77.          checkConnection();
  78.          try (PreparedStatement statement = conn.prepareStatement(query)) {
  79.             queryUpdate(statement);
  80.          } catch (Exception e) {
  81.             e.printStackTrace();
  82.          }
  83.       }
  84.       
  85.       public void queryUpdate(PreparedStatement statement) {
  86.          checkConnection();
  87.          try {
  88.             statement.executeUpdate();
  89.          } catch (Exception e) {
  90.             e.printStackTrace();
  91.          } finally {
  92.             try {
  93.                statement.close();
  94.             } catch (Exception e) {
  95.                e.printStackTrace();
  96.             }
  97.          }
  98.       }
  99.       
  100.       public ResultSet query(String query) {
  101.          checkConnection();
  102.          try {
  103.             return query(conn.prepareStatement(query));
  104.          } catch (Exception e) {
  105.             e.printStackTrace();
  106.          }
  107.          return null;
  108.       }
  109.       
  110.       public ResultSet query(PreparedStatement statement) {
  111.          checkConnection();
  112.          try {
  113.             return statement.executeQuery();
  114.          } catch (Exception e) {
  115.             e.printStackTrace();
  116.          }
  117.          return null;
  118.       }
  119.       
  120.       public Connection getConnection() {
  121.          return this.conn;
  122.       }
  123.       
  124.       private void checkConnection() {
  125.          try {
  126.             if (this.conn == null || !this.conn.isValid(10) || this.conn.isClosed()) openConnection();
  127.          } catch (Exception e) {
  128.             e.printStackTrace();
  129.          }
  130.       }
  131.       
  132.       public Connection openConnection() throws Exception {
  133.          Class.forName("com.mysql.jdbc.Driver");
  134.          return this.conn = DriverManager.getConnection("jdbc:mysql://" + this.host + ":" + this.port + "/" + this.database, this.user, this.password);
  135.       }
  136.       
  137.       public void closeConnection() {
  138.          try {
  139.             this.conn.close();
  140.          } catch (SQLException e) {
  141.             e.printStackTrace();
  142.          } finally {
  143.             this.conn = null;
  144.          }
  145.       }
  146.    }
  147. }

Benutzung:
Code: Alles auswählen
  1. AsyncMySQL sql = new AsyncMySQL(Plugin owner, String host, int port, String user, String password, String database);
  2. sql.update(String query);
  3. sql.update(PreparedStatement statement);
  4. sql.query(String query, Consumer<ResultSet> consumer);
  5. sql.query(PreparedStatement statement, Consumer<ResultSet> consumer);
Die Query Methoden geben über den Consumer das ResultSet zurück.
Ein Consumer kann etweder ganz normal instanziert werden (ist ein Interface), aber noch einfacher geht es mit Lambda-Expressions.
Zuletzt geändert von Jofkos am Mo 1. Dez 2014, 20:28, insgesamt 5-mal geändert.
Jofkos

...........

..Bild
Benutzeravatar
Jofkos
 
Beiträge: 1537
Registriert: So 16. Jun 2013, 22:45

Re: MySQL Abfragen einfach asynchron im Hintergrund

Beitragvon Summerfeeling » So 30. Nov 2014, 00:02

Schöne Klasse.
Werde ich sicherlich irgendwann mal gebrauchen können.

Danke für die Mühe!
Grüße
Summerfeeling | Timo
Benutzeravatar
Summerfeeling
 
Beiträge: 1300
Registriert: Sa 15. Jun 2013, 18:43
Wohnort: Viersen

Re: MySQL Abfragen einfach asynchron im Hintergrund

Beitragvon crysis992 » So 30. Nov 2014, 06:04

Jofkos hat geschrieben:Ich habe zusammen mit @IK_Raptor
Die Query Methoden geben über den Consumer das ResultSet zurück.
Ein Consumer kann etweder ganz normal instanziert werden (ist ein Interface), aber noch einfacher geht es mit Lambda-Expressions.


Ein Beispiel oder Tutorial für das wäre nicht schlecht :/
Benutzeravatar
crysis992
 
Beiträge: 148
Registriert: So 16. Jun 2013, 11:48

Re: MySQL Abfragen einfach asynchron im Hintergrund

Beitragvon Sep2703 » So 30. Nov 2014, 09:06

Gute Arbeit!

Ich stelle mir nur gerade folgendes Szenario vor:

- Ein Spieler möchte herausfinden, wie viele Kills er hat
- Die Kills werden mit dem Spieler als Datensatz in einer MySQL-DB abgespeichert
- Die Abfrage darf den Hauptthread nicht einführen, sie wird also asynchron ausgeführt

Mal ein Beispiel als Pseudocode:
Code: Alles auswählen
  1. method viewKills(Player p) {
  2. result = async_fetch(p - getName())
  3. Player - sendMessage("Du hast " + result + " Kills");
  4. }


Würde der Hauptthread jetzt nicht solange warten, bis ein ResultSet vorhanden ist?
Oder würde der Rest einfach ausgeführt werden, obwohl das ResultSet noch null ist?
Du möchtest programmieren lernen oder dein Bukkit-/Spigot-Wissen erweitern?
Hier habe ich für dich kostenlose Tutorials: https://youtube.com/janhektor
Benutzeravatar
Sep2703
 
Beiträge: 677
Registriert: Mi 8. Jan 2014, 15:13
Wohnort: 127.0.0.1

Re: MySQL Abfragen einfach asynchron im Hintergrund

Beitragvon IK_Raptor » So 30. Nov 2014, 09:41

Sep2703 hat geschrieben:Gute Arbeit!

Ich stelle mir nur gerade folgendes Szenario vor:

- Ein Spieler möchte herausfinden, wie viele Kills er hat
- Die Kills werden mit dem Spieler als Datensatz in einer MySQL-DB abgespeichert
- Die Abfrage darf den Hauptthread nicht einführen, sie wird also asynchron ausgeführt

Mal ein Beispiel als Pseudocode:
Code: Alles auswählen
  1. method viewKills(Player p) {
  2. result = async_fetch(p - getName())
  3. Player - sendMessage("Du hast " + result + " Kills");
  4. }


Würde der Hauptthread jetzt nicht solange warten, bis ein ResultSet vorhanden ist?
Oder würde der Rest einfach ausgeführt werden, obwohl das ResultSet noch null ist?


Nein, dafür haben wir bei der query ein Consumer<ResultSet> eingefügt. ;)
Benutzeravatar
IK_Raptor
 
Beiträge: 609
Registriert: Mo 12. Aug 2013, 15:37

Re: MySQL Abfragen einfach asynchron im Hintergrund

Beitragvon Jofkos » So 30. Nov 2014, 11:18

crysis992 hat geschrieben:Ein Beispiel oder Tutorial für das wäre nicht schlecht :/

Ein Consumer ist einfach ein Interface, was eine Methode hat, unzwar accept(T t)
Das heisst, du kannst es ganz einfach so benutzen:
Code: Alles auswählen
  1.             sql.query("*query*", new Consumer<ResultSet>() {
  2.                
  3.                @Override
  4.                public void accept(ResultSet t) {
  5.                   System.out.println(t.toString()); // irgendwas mit dem ResultSet machen
  6.                }
  7.             });
In Java 8 geht das noch viel "kürzer", dass sieht dann so aus:
Code: Alles auswählen
  1.                sql.query("*query*", t -> System.out.println(t.toString()));
Jofkos

...........

..Bild
Benutzeravatar
Jofkos
 
Beiträge: 1537
Registriert: So 16. Jun 2013, 22:45

Re: MySQL Abfragen einfach asynchron im Hintergrund

Beitragvon ilouHD » So 30. Nov 2014, 11:59

Seir wann gibt es Java 8?

Egal. Danke für diese Klasse. Werde sie bestimmt gut gebrauchen können.
Bild
Benutzeravatar
ilouHD
 
Beiträge: 1733
Registriert: Do 9. Jan 2014, 14:49

Re: MySQL Abfragen einfach asynchron im Hintergrund

Beitragvon Ch4t4r » So 30. Nov 2014, 12:29

Java 8? Seit mehreren Monaten (18.03.14)
Benutzeravatar
Ch4t4r
 
Beiträge: 455
Registriert: So 7. Jul 2013, 12:44

Re: MySQL Abfragen einfach asynchron im Hintergrund

Beitragvon leNic » So 30. Nov 2014, 13:56

Danke, die Klasse kommt mir sehr gelegen! :)
EDIT:
Wie funktioniert das ganze mit dem Consumer eigentlich? Mal angenommen ich möchte etwas auslesen:
Code: Alles auswählen
  1. sql.query("SELECT * WHERE players LIKE '%" + p.getUniqueId().toString() + "%'", consumer);
Benutzeravatar
leNic
 
Beiträge: 168
Registriert: Fr 6. Jun 2014, 18:23

Re: MySQL Abfragen einfach asynchron im Hintergrund

Beitragvon Jofkos » So 30. Nov 2014, 17:29

introlous hat geschrieben:Danke, die Klasse kommt mir sehr gelegen! :)
EDIT:
Wie funktioniert das ganze mit dem Consumer eigentlich? Mal angenommen ich möchte etwas auslesen:
Code: Alles auswählen
  1. sql.query("SELECT * WHERE players LIKE '%" + p.getUniqueId().toString() + "%'", consumer);

Jofkos hat geschrieben:
crysis992 hat geschrieben:Ein Beispiel oder Tutorial für das wäre nicht schlecht :/

Ein Consumer ist einfach ein Interface, was eine Methode hat, unzwar accept(T t)
Das heisst, du kannst es ganz einfach so benutzen:
Code: Alles auswählen
  1.             sql.query("*query*", new Consumer<ResultSet>() {
  2.                
  3.                @Override
  4.                public void accept(ResultSet t) {
  5.                   System.out.println(t.toString()); // irgendwas mit dem ResultSet machen
  6.                }
  7.             });
In Java 8 geht das noch viel "kürzer", dass sieht dann so aus:
Code: Alles auswählen
  1.                sql.query("*query*", t -> System.out.println(t.toString()));

Der Consumer ist einfach wie eine Runnable, die in der Run Methode noch ein Argument annimmt (hier: ein ResultSet)
Jofkos

...........

..Bild
Benutzeravatar
Jofkos
 
Beiträge: 1537
Registriert: So 16. Jun 2013, 22:45

Nächste

Zurück zu Anleitungen

Wer ist online?

Mitglieder in diesem Forum: Bing [Bot] und 1 Gast

cron