Come scrivere una classe corretta per connettersi al database in Java

4

Attualmente sto scrivendo un'applicazione e sto lottando con la decisione su come progettare correttamente una classe per connettersi a un database. Mi è venuta in mente una cosa del genere:

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();
    }
}

Inoltre, in questa classe ho metodi per estrarre qualcosa dal database o dall'inserto e così via, e per ogni metodo creare un PrepareStatement e ResultSet e altri oggetti separati.

La mia domanda è se questo approccio è corretto, in qualche modo sbagliato, o terribilmente sbagliato. Sarò felice per ogni suggerimento sulla progettazione di una buona classe di comunicazione e su come lavorare correttamente con i database.

Uso un database MySQL e JDBC per la comunicazione.

    
posta Piter _OS 06.01.2017 - 18:48
fonte

4 risposte

2

Preferisco un design a due classi in connessione a un database. Questo approccio è particolarmente efficace nella comunicazione con più database all'interno di una singola applicazione:

  • La Prima classe (CommDB) contiene un codice generico per la connessione ai DB e la manipolazione con i loro dati.
  • La seconda classe è un DB Proxy (MyDB) che trasporta un codice specifico del DB. Ovviamente, in un caso di più DB, ogni DB deve avere la propria classe proxy.

Per essere più specifici, ad esempio, il metodo select in CommDB ha un aspetto simile al seguente:

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

e un codice specifico per ottenere informazioni utente da MyDB può essere simile a:

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
    
risposta data 12.01.2017 - 05:47
fonte
2

Esistono vari modi per connettersi a un database relazionale per archiviare e recuperare informazioni. A seconda delle tue esigenze puoi procedere con un'implementazione di basso livello o una versione più alta.

Potresti utilizzare direttamente JDBC . Hai bisogno di un driver che sappia come parlare al tuo particolare database, apri una connessione, prepari una dichiarazione con alcune query SQL, imposta i parametri necessari per l'istruzione (se presente), esegue l'istruzione, recupera un set di risultati, itera il set di risultati per creare oggetti dai risultati, quindi chiude le risorse che hai utilizzato (set di risultati, istruzione , connessione).

Questo è il modo più basso per farlo. Ma ha alcuni svantaggi:

  • Il codice della piastra di caldaia è molto elevato: ottieni connessione, crea istruzioni, esegui istruzioni, passa in rassegna i risultati, costruisci oggetti, rilascia risorse utilizzate. Devi fare queste ogni volta che vuoi eseguire alcuni SQL. Solo SQL è diverso ogni volta, il resto lo devi fare ancora, ancora e ancora.
  • si apre una connessione al database ogni volta che si esegue una query. C'è un sovraccarico in questo e, a seconda di quante query si eseguono alla volta, si potrebbe finire per aprire troppe connessioni. Alcuni database potrebbero avere limitazioni per client, quindi non puoi andare troppo in alto.

Per limitare le connessioni aperte potresti utilizzare un pool di connessioni come Apache DBCP, C3P0, HikariCP, ecc. Hai ancora lo stesso codice della piastra di riscaldamento, ma ora invece di creare e chiudere una connessione, prendi in prestito e restituisci uno al pool. Più efficiente.

Ora, dal momento che il piatto della caldaia è sempre lo stesso, perché non spostarlo in qualche framework o libreria che lo fa per te e ti concentri solo a scrivere l'SQL. Questo è ciò che fa un mappatore di dati come MyBatis , ad esempio. Lo si configura una volta, si scrivono gli SQL necessari e si associano ai metodi, si dice a MyBatis come mappare il risultato da una riga all'altra e tutta la piastra della caldaia viene gestita da MyBatis. Esegui un metodo e recupera gli oggetti che desideri.

Con MyBatis hai solo bisogno di scrivere l'SQL. Ma alcune persone non vogliono nemmeno preoccuparsene. Hai codice della piastra della caldaia e le connessioni gestite da qualche libreria / framework per te, ma perché non eliminare anche SQL?

Questo è ciò che ORM come fa Hibernate. Si associano le classi alle tabelle e poi Hibernate gestisce tutto per te. Genera l'SQL necessario quando si desidera salvare o recuperare i dati dal database. Una volta configurato Hibernate, puoi fingere che il database non esista (almeno per un po ').

Ciascuno di questi metodi presenta vantaggi e svantaggi.

  • con JDBC devi scrivere molto codice della piastra, gestire le transazioni da solo, assicurarti di non perdere le risorse, ecc. È di basso livello;
  • con i mapper dei dati è necessario scrivere gli SQL. Il data mapper non pretende che non ci sia un database, devi affrontarlo.
  • con gli ORM puoi fingere che non ci sia alcun database relazionale coinvolto. Hai a che fare solo con gli oggetti. Gli ORM sono ideali per le applicazioni CRUD ma per gli altri, un ORM potrebbe metterti nei guai. C'è questa cosa chiamata disadattamento dell'impedenza relazionale-oggetto che mostra la sua brutta testa. E quando lo fa, le prestazioni sono di solito la prima cosa che va a finire.

Queste sono le tue opzioni. Guarda la tua applicazione e vedi quale soluzione potrebbe essere più appropriata. Considerando la tua domanda, potresti voler usare qualcosa di leggero (non basso come JDBC diretto, e non tanto alto quanto Hibernate).

Ma non reinventare la ruota . Qualcosa come Commons DbUtils per esempio può essere un buon punto di partenza. Prende il codice piastra caldaia JDBC lontano da te, senza modificare / aggiungere molto al modo in cui interagisci con un database.

    
risposta data 07.01.2017 - 14:36
fonte
0

Quindi per chiamare la query si dovrebbe fare qualcosa di simile:

    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));

I metodi avranno un aspetto simile a questo:

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;
}
    
risposta data 03.09.2018 - 06:23
fonte
-1

Per piccoli compiti non è necessario portare mostri come Hibernate in un'immagine. Se vuoi eseguire query SQL dirette senza layer ORM, il tuo approccio è buono. Non dimenticare di caricare la classe del conducente in anticipo.

public DatabaseConnector(String url, String user, String password) {

    Class.forName("com.mysql.jdbc.Driver");

    databaseConnection = DriverManager.getConnection(url, user, password);

}

Per altri aspetti dipende da te come gestire la connessione, per quanto tempo vorresti tenerla aperta, riutilizzarla o meno, e così via. Lo stesso vale per gli stati preparati ...

    
risposta data 06.01.2017 - 19:05
fonte

Leggi altre domande sui tag