web-dev-qa-db-fra.com

Comment écrire une classe appropriée pour se connecter à la base de données dans Java

J'écris actuellement une application et j'ai du mal à décider comment concevoir correctement une classe pour se connecter à une base de données. J'ai trouvé quelque chose comme ça:

public class DatabaseConnector {
    private Connection databaseConnection = null;

    public DatabaseConnector(String url, String user, String password) {
        databaseConnection = DriverManager.getConnection(url, user, password);
    }

    public void close() throws SQLException {
        databaseConnection.close();
    }
}

De plus, dans cette classe, j'ai des méthodes pour extraire quelque chose de la base de données ou insérer, etc., et pour chaque méthode, créez un PrepareStatement et ResultSet et d'autres objets séparés.

Ma question est de savoir si cette approche est correcte, en quelque sorte erronée ou terriblement erronée. Je serai heureux de chaque conseil sur la conception d'un bon cours de communication et sur la façon de travailler correctement avec des bases de données.

J'utilise une base de données MySQL et JDBC pour la communication.

4
Piter _OS

Je préfère une conception à deux classes pour me connecter à une base de données. Cette approche est particulièrement efficace pour communiquer avec plusieurs bases de données au sein d'une même application:

  • La première classe (CommDB) contient un code générique pour se connecter aux bases de données et manipuler avec leurs données.
  • La deuxième classe est un proxy DB (MyDB) qui porte un code spécifique DB. Évidemment, dans le cas de plusieurs bases de données, chaque base de données doit avoir sa propre classe proxy.

Pour être plus précis, par exemple, la méthode select dans CommDB ressemble à ceci:

public class CommDB
{/** This class contains a generic code for data manipulation */

    public TreeMap<String,HashMap<String,String>> 
    select(Connection conn, String selectQuery) 
    { /** This is a generic method for the select operation */

        TreeMap<String,HashMap<String,String>> selectResult = 
                                    new TreeMap<String,HashMap<String,String>>();
        String[] keys = selectQuery.replace(" ","").replace("SELECT", "").split("FROM")[0].split(",");

        try {
            PreparedStatement stmt = conn.prepareStatement(selectQuery);
            ResultSet rs = stmt.executeQuery();
            while (rs.next()) {
                HashMap<String,String> eachResult = new HashMap<String,String>();
                for (int i=1; i<keys.length; i++) { 
                    eachResult.put(keys[i],rs.getString(i+1));              
                } // for
                selectResult.put(rs.getString(1),eachResult);
            } // while

        } catch(SQLException sqlExc) {
            System.out.println(sqlExc.getMessage());
        } // try-catch

        return selectResult;
    } // select()

} // class CommDB

et un code spécifique pour obtenir des informations utilisateur de MyDB peut ressembler à:

public class MyDB
{ /** This is MyDB Proxy Class */
    String myDbUrl = "jdbc:mysql://MyDB/mySchema";
    String myDbDriver = "com.mysql.jdbc.Driver";
    String myDbUser = "myName";
    String myDbPwd = "myPassword";
    CommDB db = new CommDB();

    public TreeMap<String,HashMap<String,String>> 
    getUsers(String namePattern) 
    { /** This method is specific for USERS data */     
        TreeMap<String,HashMap<String,String>> users = 
                new TreeMap<String,HashMap<String,String>>();           
        String selectUsers = 
         "SELECT userID, firstName, lastName, address, phone FROM USERS " + 
            "WHERE lastName like '%" + namePattern + "%'";

        Connection conn = null;
        try {           
            conn = db.connect(myDbUrl,myDbDriver,myDbUser,myDbPwd);
            users = db.select(conn, selectUsers);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        } finally {
            try {
                if (conn != null) { conn.close(); }
            } catch (SQLException sqlExc) {
                System.out.println(sqlExc.getMessage());
            } // try-catch
        } // try-catch-finally

        return users;
    } // getUsers()

} // class MyDB
2
Noviff

Il existe différentes façons de se connecter à une base de données relationnelle pour stocker et récupérer des informations. Selon vos besoins, vous pouvez opter pour une implémentation de bas niveau ou supérieure.

Vous pourriez tiliser directement JDBC . Vous avez besoin d'un pilote qui sait comment parler à votre base de données particulière, vous ouvrez une connexion, vous préparez une instruction avec une requête SQL, définissez les paramètres nécessaires pour l'instruction (le cas échéant), exécutez l'instruction , récupérez un jeu de résultats, itérez le jeu de résultats pour créer des objets à partir des résultats, puis fermez les ressources que vous avez utilisées (jeu de résultats, instruction, connexion).

C'est la façon la plus simple de procéder. Mais cela présente certains inconvénients:

  • Vous avez beaucoup de code de plaque de chaudière: obtenir une connexion, créer une instruction, exécuter une instruction, parcourir les résultats, créer des objets, libérer des ressources utilisées. Vous devez les faire chaque fois que vous souhaitez exécuter du SQL. Seul le SQL est différent à chaque fois, le reste vous devez le faire encore et encore et encore.
  • vous ouvrez une connexion à une base de données chaque fois que vous exécutez une requête. Il y a des frais généraux impliqués dans cela et selon le nombre de requêtes que vous exécutez à la fois, vous pourriez finir par ouvrir trop de connexions. Certaines bases de données peuvent avoir des limites par client, vous ne pouvez donc pas aller trop haut.

Pour limiter les connexions que vous ouvrez, vous pouvez tiliser un pool de connexions comme Apache DBCP, C3P0, HikariCP, etc. Vous avez toujours le même code de plaque de chaudière, mais maintenant au lieu de créer et de fermer une connexion, vous empruntez et en remettre un à la piscine. Plus efficace.

Maintenant, puisque la plaque de la chaudière est la même à chaque fois, pourquoi ne pas l'éloigner dans un cadre ou une bibliothèque qui le fait pour vous et vous vous concentrez simplement sur l'écriture du SQL. C'est ce que fait un mappeur de données comme MyBatis , par exemple. Vous le configurez une fois, écrivez les SQL dont vous avez besoin et les mappez aux méthodes, dites à MyBatis comment mapper le résultat des lignes aux objets, et toute la plaque de la chaudière est gérée par MyBatis pour vous. Exécutez une méthode et récupérez les objets souhaités.

Avec MyBatis, il vous suffit d'écrire le SQL. Mais certaines personnes ne veulent même pas s'en préoccuper. Vous avez le code de plaque de chaudière et les connexions gérées par une bibliothèque/un framework pour vous, mais pourquoi ne pas vous débarrasser de SQL également?

C'est ce que ORMs comme le fait Hibernate. Vous mappez les classes aux tables, puis Hibernate gère tout pour vous. Il génère le SQL nécessaire lorsque vous souhaitez enregistrer ou récupérer des données de la base de données. Une fois que vous avez configuré Hibernate, vous pouvez prétendre que la base de données n'existe pas (au moins pendant un certain temps).

Chacune de ces méthodes présente des avantages et des inconvénients.

  • avec JDBC, vous devez écrire beaucoup de code de plaque de chaudière, gérer vous-même les transactions, vous assurer de ne pas perdre de ressources, etc. C'est un niveau bas;
  • avec les mappeurs de données, vous devez écrire les SQL. Le mappeur de données ne prétend pas qu'il n'y a pas de base de données, vous devez y faire face.
  • avec les ORM, vous pouvez faire comme si aucune base de données relationnelle n'était impliquée. Vous ne traitez qu'avec des objets. Les ORM sont parfaits pour les applications CRUD mais pour d'autres, un ORM peut vous causer des ennuis. Il y a cette chose appelée non-correspondance d'impédance relationnelle-objet qui montre que c'est la tête laide. Et quand c'est le cas, la performance est généralement la première chose qui va dans les égouts.

Ce sont vos options. Examinez votre application et voyez quelle solution pourrait être la plus appropriée. Compte tenu de votre question, vous souhaiterez peut-être utiliser quelque chose de léger (pas aussi bas que JDBC direct et pas aussi haut que Hibernate).

Mais ne réinventez pas la roue . Quelque chose comme Commons DbUtils par exemple peut être un bon point de départ. Il vous éloigne du code de plaque de la chaudière JDBC, sans modifier/ajouter beaucoup à la façon dont vous interagissez avec une base de données.

2
Bogdan

Donc, pour appeler la requête, vous feriez quelque chose comme ceci:

    String Querry = "SELECT seatID,movieID,Tanda,seatNum,isBooked,BookedBy FROM ROOT.SEATS";
    Map<String, List< Object>> map = getListQuerry(Querry);
    map.forEach((key, value) -> System.out.println(key + ":" + value));

Les méthodes ressembleront à ceci:

Map<String, List< Object>> getListQuerry(String query) {
    System.out.println("getListQuerry will run SQL Querry:\n\t\t" + query);

    Map<String, List< Object>> result = new HashMap<>();
    String[] keys = query.replace(" ", "").replace("SELECT", "").split("FROM")[0].split(",");
    for (String Key : keys) {
        result.put(Key, new ArrayList<>());
    }

    try (Connection Connection = DriverManager.getConnection(Host, DBUsername, DBpassword)) {
        PreparedStatement stmt = Connection.prepareStatement(query, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
        ResultSet resultSet = stmt.executeQuery();

        while (resultSet.next()) {
            for (int i = 1; i < keys.length; i++) {
                result.get(keys[i]).add(resultSet.getInt(keys[i]));
            }
        }
    } catch (SQLException ex) {
        Logger.getLogger(Stage1Bootup.class.getName()).log(Level.SEVERE, null, ex);
        System.out.println("Query failed to run");
    }
    return result;
}
0
Guilder Milliner