Partage
  • Partager sur Facebook
  • Partager sur Twitter

Singleton pour une connexion à une base de données

SQLite

Sujet résolu
    13 janvier 2018 à 17:50:01

    Bonjour,

    Désolé si un topic a déjà été créé un peu plus bas pour un cas similaire mais ma question diffère un peu de celle de son auteur.

    J'ai donc créé un programme qui doit se connecter à une base de données SQLite en mono-utilisateur en local.

    Pour économiser des ressources j'ai suivi le tuto suivant : https://openclassrooms.com/courses/apprenez-a-programmer-en-java?status=published

    et utilisé un singleton pour me connecter à ma base :

    public class DBInitialize {
        
        private static Connection connection = null;
        private static String url = "jdbc:sqlite:db/cryption.db";
        private static String sql = "CREATE TABLE IF NOT EXISTS t_notes (\n"
                    + "n_ID text PRIMARY KEY,\n"
                    + "n_TITLE text NOT NULL,\n"
                    + "n_CONTENT text NOT NULL,\n"
                    + "n_FOLDER text,\n"
                    + "n_DATE text,\n"
                    + "n_ALERT boolean \n"
                    + ");";
        
        
        public static Connection getInstance() {
     
            if (connection == null) {
                try {
                    connection = DriverManager.getConnection(url);
                    DatabaseMetaData meta = connection.getMetaData();
                    System.out.println("The driver name is " + meta.getDriverName());
                    System.out.println("Connection to SQLite has been established.");
                } catch (SQLException e) {
                    System.out.println(e.getMessage());
                }
            }
            return connection;
        }
        
        public static void initializationDB() {
            if (connection != null) {
                try (Statement stmt = connection.createStatement()) {
                        stmt.execute(sql);
                        stmt.close();
                } catch (SQLException e) {
                    System.out.println(e.getMessage());
                }
            }
        }
        
    }

    De ce côté là, tout fonctionne. J'ai donc utilisé une première fois l'instance dans mon code et refermé de suite après par un .close().

    J'ai ensuite voulu ajouter une nouvelle Note (mémo) dans la base avec les codes suivants :

    newNote = new Note(newNoteTitle, newNoteContent, newNoteFolder, newNoteDate, newNoteAlert);
                DAO<Note> createNote = new NoteDAO(DBInitialize.getInstance());
                createNote.create(newNote);

    (donc une nouvelle instance mais toujours unique puisque la précédente a été fermée).

    et

    public class NoteDAO extends DAO<Note> {
        
        public NoteDAO(Connection conn) {
            super(conn);
        }
    
        public boolean create(Note obj) {
            String table = "t_notes";
            String sql = "INSERT INTO " + table + " VALUES ('"
                    + IDGenerator.getIDGen() + "', '"
                    + obj.getTitleNote() + "', '"
                    + obj.getContentNote() + "', '"
                    + obj.getFolderNote() + "', '"
                    + obj.getDateNote() + "', '"
                    + obj.getAlertNote() + "')";
            try {
                PreparedStatement prep = this.connect.prepareStatement(sql);
                prep.executeUpdate();
            } catch (SQLException ex) {
                Logger.getLogger(NoteDAO.class.getName()).log(Level.SEVERE, null, ex);
            }
            return false;
        }
    
        public boolean delete(Note obj) {
            System.out.println("OK");
            return false;
        }
       
        public boolean update(Note obj) {
            System.out.println("OK");
            return false;
        }
       
        public Note find(int id) {
            Note note = new Note();      
          
            /*try {
                ResultSet result = this.connect.createStatement(
                ResultSet.TYPE_SCROLL_INSENSITIVE,
                ResultSet.CONCUR_READ_ONLY).executeQuery("SELECT * FROM t_notes WHERE n_id = " + id);
                if(result.first())
                    note = new Note(
                    id,
                    result.getString("elv_nom"),
                    result.getString("elv_prenom"
                ));         
            } catch (SQLException e) {
                e.printStackTrace();
            }*/
            return note;
        }
    }
    public abstract class DAO<T> {
        
        protected Connection connect = null;
       
        public DAO(Connection conn){
            this.connect = conn;
        }
       
        public abstract boolean create(T obj);

    Seulement quand je compile, je reçois un message d'erreur me disant que la connexion a été fermé et donc que l'opération d'insertion dans la base n'a pas fonctionnée. 

    L'origine du problème est bien le close() dans ma fonction main puisque si je le retire tout est bon, mais si on ferme une connexion normalement dans le singleton on peut récréer une instance car la connexion == null.

    Je ne comprends pas.

    Merci d'avance.




    • Partager sur Facebook
    • Partager sur Twitter
    Since 2007 (c)
      14 janvier 2018 à 19:06:19

      Bonjour,

      Premièrement je doute que la compilation te dise que la connexion est déjà close, ce ne serait pas plutôt l'exécution ;)

      Sinon ton problème peut se résoudre très facilement (j'ai donné le code hier sur ce forum) en remplaçant

      if (connection == null) {

      par

      if (connection == null || connection.isClosed()) {

      Sinon pour information cette implémentation n'est pas vraiment un Singleton (qui veut dire une seule instance) car dans le cas présent la classe n'est pas instanciée. Ce serait plutôt une classe helper. Dans le code auquel je fais mention au-dessus je donne un exemple d'implémentation de Singleton pour du mono-thread.

      Sinon tu n'es pas obligé de fermer la connexion après chaque requête, à condition de t'assurer de la fermer en fin d'exécution


      -
      Edité par JDesm 14 janvier 2018 à 19:16:15

      • Partager sur Facebook
      • Partager sur Twitter
        14 janvier 2018 à 22:55:23

        janv. 14, 2018 10:45:01 PM fr.cryption.model.NoteDAO create
        GRAVE: null
        java.sql.SQLException: database connection closed

        Bah voilà ce que je reçois dans la console du coup je pensais que c'était bien la connexion qui close. En tout cas la condition que tu as ajouté fonctionne parfaitement. Par contre du coup je ne comprend pas, si connexion est bien égal à "null" elle est forcément close non ? pourquoi rajouter un isclosed() après ?
        Et pour la fermeture je ne vois pas comment fermer la connexion seulement en fin de programme à part en mettant un listener en cas de clic sur la croix rouge.
        Merci pour aide !
        • Partager sur Facebook
        • Partager sur Twitter
        Since 2007 (c)
          15 janvier 2018 à 6:53:56

          Cette condition teste 2 cas

          • la connexion est nulle (et dans ce cas elle n'est pas closed, tu as raison)
          • OU la connexion existe mais on a appelé la méthode close() dessus, et elle ne peut plus être utilisée

          Le listener sur la croix rouge me semble une bonne solution, si c'est le moyen de fermer l'application.

          Sinon tu peux ajouter dans ta classe DBInitialize, lorsque tu crées la connexion

          Runtime.getRuntime().addShutdownHook(new Thread() {
          	@Override
          	public void run()
          	{
          		// quelque chose du style ...
          		connection.close();
          	}
          });



          • Partager sur Facebook
          • Partager sur Twitter
            15 janvier 2018 à 14:10:13

            Ok super, je te remercie je vais creuser tout ça!

            • Partager sur Facebook
            • Partager sur Twitter
            Since 2007 (c)

            Singleton pour une connexion à une base de données

            × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
            × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
            • Editeur
            • Markdown