ServerPlugin MySQL, wie geht es noch?

Dieses Thema im Forum "Programmierung" wurde erstellt von Joans96, 7. April 2015.

  1. Joans96
    Offline

    Joans96

    Registriert seit:
    9. März 2014
    Beiträge:
    37
    Minecraft:
    Joans96
    Hallo liebe Community,
    ich möchte euch mal meine MySQL-Methode zeigen, mit der ich normalerweise arbeite.

    Code (Text):
    1.  
    2. package de.PixelCrafter.Main.MySQL;
    3.  
    4. import java.sql.Connection;
    5. import java.sql.DriverManager;
    6. import java.sql.ResultSet;
    7. import java.sql.SQLException;
    8. import java.sql.Statement;
    9.  
    10. import org.bukkit.Bukkit;
    11.  
    12. import de.PixelCrafter.Configuration.Messages;
    13. import de.PixelCrafter.Main.MainPlugin;
    14.  
    15. public class MySQL
    16. {
    17.     public static Connection connection;
    18.     private static int MySQLSchedulerID;
    19.  
    20.     public static void onConnect()
    21.     {
    22.         try
    23.         {
    24.             connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/"+ MySQLData.database, MySQLData.username, MySQLData.password);
    25.             System.out.println(Messages.c_prefix + "MySQL-Verbindung hergestellt!");
    26.        
    27.             onReconnectScheduler();
    28.         }
    29.    
    30.         catch (SQLException e)
    31.         {
    32.             System.err.println(Messages.c_prefix + "MySQL-Verbindung konnte nicht hergestellt werden!");
    33.             e.printStackTrace();
    34.         }
    35.     }
    36.  
    37.     public static void onDisconect()
    38.     {
    39.         if(connection != null )
    40.         {
    41.             try
    42.             {
    43.                 connection.close();
    44.                 System.out.println(Messages.c_prefix + " MySQL-Verbindung beendet!");
    45.            
    46.                 if(Bukkit.getScheduler().isCurrentlyRunning(MySQLSchedulerID))
    47.                 {
    48.                     Bukkit.getScheduler().cancelTask(MySQLSchedulerID);
    49.                 }
    50.             }
    51.        
    52.             catch (SQLException e)
    53.             {
    54.                 e.printStackTrace();
    55.                 System.err.println(Messages.c_prefix + " MySQL-Verbindung konnte nicht getrennt werden!");
    56.             }
    57.         }
    58.     }
    59.  
    60.     private static void onReconnectScheduler()
    61.     {
    62.         MySQLSchedulerID = Bukkit.getScheduler().scheduleSyncRepeatingTask(MainPlugin.getInstance(), new Runnable()
    63.         {
    64.             public void run()
    65.             {
    66.                 onReconnect();
    67.             }
    68.         }, 20 * 60 * 60 *6, 20 * 60 * 60 *6);
    69.     }
    70.  
    71.     private static void onReconnect()
    72.     {
    73.         if(connection != null)
    74.         {
    75.             try
    76.             {
    77.                 connection.close();
    78.                 System.out.println(Messages.c_prefix + " MySQL-Verbindung beendet!");
    79.                 }
    80.        
    81.             catch (SQLException e)
    82.             {
    83.                 System.err.println(Messages.c_prefix + " MySQL-Verbindung konnte nicht getrennt werden!");
    84.                 e.printStackTrace();
    85.             }
    86.         }
    87.    
    88.         Bukkit.getScheduler().scheduleSyncDelayedTask(MainPlugin.getInstance(), new Runnable()
    89.         {
    90.             public void run()
    91.             {
    92.                 try
    93.                 {
    94.                     connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/"+ MySQLData.database, MySQLData.username, MySQLData.password);
    95.                     System.out.println(Messages.c_prefix + "MySQL-Verbindung hergestellt!");
    96.                 }
    97.            
    98.                 catch (SQLException e)
    99.                 {
    100.                     System.err.println(Messages.c_prefix + "MySQL-Verbindung konnte nicht hergestellt werden!");
    101.                     e.printStackTrace();
    102.                 }
    103.             }
    104.         }, 1L);
    105.     }
    106.  
    107.     public static void onUpdate(String qry)
    108.     {
    109.         try
    110.         {
    111.             Statement stmt = connection.createStatement();
    112.             stmt.executeUpdate(qry);
    113.         }
    114.         catch (SQLException e)
    115.         {
    116.             e.printStackTrace();
    117.         }
    118.     }
    119.  
    120.     public static ResultSet onQuery(String qry)
    121.     {
    122.         ResultSet rs = null;
    123.    
    124.         try
    125.         {
    126.             Statement stmt = connection.createStatement();
    127.             rs = stmt.executeQuery(qry);
    128.         }
    129.         catch (SQLException e)
    130.         {
    131.             e.printStackTrace();
    132.         }
    133.    
    134.         return rs;
    135.     }
    136. }
    137.  

    Um kurz ein Paar Worte dazu zu sagen:
    Im "onEnable()"-Teil des Plugins wird die Funktion "onConnect()" ausgeführt, im "onDisable()"-Teil wird die Funktion "onDisconnect" aufgerufen.
    Die Funktion "onReconnectScheduler()" und "onReconnect" dienen dazu, um die Verbindung zur Datenbank aufrecht zu erhalten, da diese sich nach ca. 8 Stunden trennt.
    Sollten noch Fragen aufkommen, werde ich diese gerne beantworten!


    Was ich nun gerne von euch wissen möchte:

    - Wie findet ihr meine Bisherige Vorgehensweise, die ich verwende?
    - Habt ihr Verbesserungsvorschläge?

    Und viel interessanter für mich:
    - Wie geht es noch?


    Ich freue mich jetzt schon mal auf konstruktive Beiträge!

    Mit österlichen Grüßen
    Joans96

    Ps: Ich hoffe, das ist der richtige Foren-Bereich für dieses Thema ^^
     
    #1
  2. Paulomart
    Offline

    Paulomart

    Registriert seit:
    3. November 2013
    Beiträge:
    148
    Ort:
    C:/Eclipse/Workspace/
    Minecraft:
    Paulomart
    Hallo,

    Wieso ist alles static?


    MfG

    Paulomart
     
    #2
    MiCrJonas gefällt das.
  3. Joans96
    Offline

    Joans96

    Registriert seit:
    9. März 2014
    Beiträge:
    37
    Minecraft:
    Joans96
    Hallo @Paulh ,
    das ist eine berechtigte Frage.

    Ich habe die Funktionen 'static' gemacht, um diese ganz einfach mit dem Klassennamen, dann einen Punkt und dann den Namen der Funktion aufrufen zu können.
    Code (Text):
    1.  
    2. MySQL.onConnect();
    3. MySQL.onDisconnect();
    4. // usw...
    5.  
    Natürlich gibt es auch andere Wege, ich habe den Weg über 'static' gewählt, weil er für mich einfacher zu merken und auch, weil ich die anderen nicht genne (>.<).
     
    #3
  4. Alles static zu makieren hört sich nicht gerade gut an. - Davon mal abgesehen, dass es nicht objektorientiert ist ein derartiges Muster einzuhalten. Datenbanken sollten möglichst mehr abstrahiert werden. Beispielsweise dadurch, dass neben MySQL auch SQLite möglich ist. (Einfacheres Auswechseln von Komponenten)

    Ein ziemlich einfaches Muster, dass MySQL selber ein Interface implementiert. Durch ein Singleton "DatabaseManager" oder ähnliches kann die implementierung aufgerufen werden.

    Deine Reconnect Methode ist im übrigen unnötig und verbraucht "unnötig viele" Resourcen. Orientiere dich am lazy-loading:

    Code (Java):
    1.  
    2. private Connection connection;    
    3. // [...]
    4. private Connection getConnection() throws SQLException {
    5.         if (connection == null || connection.isClosed() || !connection.isValid(3)) {
    6.             connection = // custom code reinit
    7.         }
    8.         return connection;
    9.     }
    Im code dann einfach getConnection() statt direktem Zugriff auf connection und man sollte keine Probleme haben connection zu verwenden. Natürlich sollte man diese auch zwischenspeichern innerhalb einer Methode, aber das ist ja trivial.

    Außerdem verwendest du Statements - pfui.

    Dein Error Handling ist ebenfalls Müll - Die Exception einfach ignorieren kann nicht gut sein.
     
    #4
    Typo, DerDr4g0n und MrGoms gefällt das.
  5. Joans96
    Offline

    Joans96

    Registriert seit:
    9. März 2014
    Beiträge:
    37
    Minecraft:
    Joans96
    Ach herrje, ich glaube ich sollte erstmal meine programmierweise überdenken, da ich fast alles in meinen Plugins 'static' habe -.-
    Wäre um Hilfe sehr dankbar, da ich leider nur die Variante mir 'static' kenne -.-
     
    #5
  6. [Dev] iTzSasukeHDxLP
    Offline

    [Dev] iTzSasukeHDxLP Ehem. Teammitglied

    Registriert seit:
    5. Januar 2014
    Beiträge:
    938
    Abgesehen davon kannste dir dein 8h Disconnect Problem auch locker flockig durch:

    Code (Text):
    1. ?autoReconnect=true
    vom Hals halten kannst.
     
    #6
  7. MuellerMH
    Offline

    MuellerMH

    Registriert seit:
    26. Februar 2015
    Beiträge:
    5
    Ort:
    Essen
    Minecraft:
    MuellerMH
    Bei Datenbank Verbindungen macht ein Static schon Sinn wenn du mit einem Singleton arbeiten willst. Dadurch sicherst du dir automatisch das es immer nur eine Verbindung zum DB Server gibt.

    Hier mal ein grobes Beispiel einer Datenbank Klasse als Singleton http://hastebin.com/yogicanero.coffee .

    Anwendungsbeispiel nur dummy Code:

    private void LogChatDummy(CustomChatEvent event)
    {
    try {
    MySQL dbConnection = MySQL.getInstance();
    String sql = "insert into chat (text, player) values (?, ?)";
    PreparedStatement query = dbConnection.getPreStat(sql);
    preparedStmt.setString (1, event.getMessage());
    preparedStmt.setString (2, event.getPlayer.getName());

    dbConnection.insertDB(preparedStmt);
    } catch (SQLException e) {
    e.printStackTrace();
    }catch (NullPointerException e) {
    e.printStackTrace();
    }
    }
     
    #7
  8. 可愛い
    Offline

    可愛い

    Registriert seit:
    19. Mai 2014
    Beiträge:
    657
    Solche MySQL Klassen machen nie Sinn, da es schon seinen Grund hat, wesshalb MySQL Statements so "bloated" sind. Man kann die Fehler nicht einfach unter den Tisch fallen lassen, man braucht diesen Zugriff, den die MySQL lib einem gibt. Wenn man darauf keine Lust hat, sollte man sich ORM ansehen. https://www.google.de/search?q=ORM+java
     
    #8
  9. MuellerMH
    Offline

    MuellerMH

    Registriert seit:
    26. Februar 2015
    Beiträge:
    5
    Ort:
    Essen
    Minecraft:
    MuellerMH
    Solche Singleton Wraper machen absolut Sinn, da sie die java.sql Lib genau da Kapselt wo es Sinn macht. Natürlich wird so eine Klasse nur im DAL genutzt da es allen anderen Klassen erstmal egal ist wie Daten verarbeitet werden. Ebenso kann man diesen Layer (Wrapper) der java.sql Lib Problemlos Zentral austauschen wenn man andere Datenbanke verwendet. Hier muss evtl dann der DAL angepasst werden wenn man von SQL auf NOSQL wechselt.
     
    #9
  10. GermanElectronix
    Offline

    GermanElectronix

    Registriert seit:
    9. März 2014
    Beiträge:
    5
    Minecraft:
    leNic
    Versucht mal einen Server mit 50+ Spielern mit dieser Klasse zu betreiben. Spätestens ab dieser Spielerzahl kommt ihr um einen Connection Pool nicht mehr herum. Ich verwende deswegen immer HikariCP.
     
    #10
  11. MuellerMH
    Offline

    MuellerMH

    Registriert seit:
    26. Februar 2015
    Beiträge:
    5
    Ort:
    Essen
    Minecraft:
    MuellerMH
    Du weißt schon das da hinter den MySQL Funktionen ein conector hängt der genau dafür gedacht ist? Den Connection Pool zu handeln?
     
    #11
  12. Typo
    Offline

    Typo

    Registriert seit:
    8. Oktober 2014
    Beiträge:
    20
    Die von manf erwähnten Punkte sind meiner Meinung nach extrem wichtig, doch würde mich sehr Interessieren wie ihr bei größeren Projekten vorgeht,da hier ja auch Aspekte wie z.B asynchrone Abfragen mehr an Wichtigkeit zunehmen.
     
    #12