IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

JDBC Java Discussion :

Comportement particulier de requêtes SQL sur SQL Server depuis une application mobile Java


Sujet :

JDBC Java

  1. #1
    Membre régulier
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Avril 2022
    Messages
    37
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Chef de projet NTIC
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2022
    Messages : 37
    Points : 79
    Points
    79
    Par défaut Comportement particulier de requêtes SQL sur SQL Server depuis une application mobile Java
    Bonjour à tous,

    Ceci est mon premier message sur le forum, je suis ravis de faire partie de cette communauté.(Enfin, de bientôt en faire partie j'imagine).
    Je viens tout droit de St@ck0v3fl0w, j'en ai marre de me faire pourrir de vote down sur mes postes par des gens complètement random qui n'expliquent même pas le pourquoi de leur action.
    Bref, revenons en au fait !

    Je suis actuellement en train de développer une appli mobile Java, sur Android Studio, et je rencontre un problème de l'ordre un peu plus global que le dev. mobile : d'où mon poste dans ce sous forum.

    Mon application est connectée à l'aide de JTDS & jdbc à une base de données MS SQL Server.(On partira du principe que la connexion en direct à la DB, c'est OK ! )
    J'arrive parfaitement à me connecter à la DB, à réaliser des executeQuery() afin de lire des données via des requêtes "SELECT".

    Cependant, lorsque j'essaie d'écrire dans ma bdd, soit à l'aide de "INSERT INTO" soit à l'aide de "UPDATE"; il... ne se passe rien. J'ai géré dans mon code toutes les exceptions pouvant se passer en inscrivant des espèces de check point dans mes Log à l'aide de Log.e(String, String), qui atteste du bon déroulement de ma requête... et rien : mes fonctions s'effectuent sans problème(Sans problème, car par exemple quand j'écris INSERT INTO table2 alors que celle ci n'existe pas, j'ai bien une SQLException ! alors que INSERT INTO table1 avec table1 existante, mes logs m'attestent que c'est ok, et preparedstatement.executeUpdate() retourne 1, ce qui sous-entendrait que 1 ligne a bien été affectée... Je deviens fou !)

    Le plus bizarre dans tout ça, c'est que lors d'un INSERT INTO dans une table s'auto-incrémentant, aucune nouvelle ligne n'est crée MAIS l'indice d'auto-incrementation augmente. Si au bout de 30 essais de requêtes j'essaie d'écrire une ligne à la main, alors son ID unique auto-incrémenté sera 31... Je deviens fou !

    Vous trouverez ci-dessous les fonctions concernées.
    J'ai bien sûr caché la connexion SQL, mais partez du principe qu'elle est OK : j'arrive bien à effectuer des requêtes SELECT.

    Gestion de la connexion :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    public static boolean setUpConnexion(String DBNAME) {
            StrictMode.ThreadPolicy policy;
            policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
            StrictMode.setThreadPolicy(policy);
     
    		VARIABLES DE CONNEXION SQL
     
            try {
               ETABLISSEMENT DE LA CONNEXION SQL A L'AIDE DE JTBS
                }
                return true;
            } catch (Exception e) {
                System.out.println("SQL ERROR: " + e.getMessage());
                e.printStackTrace();
                return false;
            }
        }
     
        public synchronized static void closeCons() {
            try {
                if (exportCon != null) {
                    exportCon.close();
                }
                mainCon.close();
            } catch (Exception e) {
                System.out.println("Erreur a la fermeture des connexions SQL:" + e.getMessage());
                e.printStackTrace();
            }
        }
    Execution des requêtes :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    public static String LOAD_PREVIOUS_H_LOT_NUMBER(String machineNumber) {
            String s = "";
            try {
                setUpConnexion("mainDB");
                ResultSet RS = executeQuery("SELECT h_lot_number FROM valve_assembly_h WHERE machine_number = '" + machineNumber + "' AND statut = 'Actif'", "mainDB");
                while (RS.next()) {
                    s = RS.getString(1);
                    Log.d("Success : ", "Lot number : " + s);
                }
                closeResultSet(RS);
            } catch (Exception e) {
                error = e.getMessage();
                Log.e("Error :", error);
                s = error;
            }
            closeCons();
            return s;
        }
     
        public static boolean UPDATE_PREVIOUS_H_LOT_STATUT(String h_lot_number_old) {
            try {
                setUpConnexion("mainDB");
                String baseQuery = "UPDATE valve_assembly_h SET statut = 'Expiré' WHERE h_lot_number = '" + h_lot_number_old + "'";
                 //PreparedStatement p = newTransact("UPDATE valve_assembly_h SET statut = 'Expiré' WHERE h_lot_number = '" + h_lot_number_old + "'", "mainDB");
                PreparedStatement toReturn = (PreparedStatement) mainCon.prepareStatement(baseQuery);
                int count = toReturn.executeUpdate();
                if (count > 0) {
                    Log.d("Sucess : ", "Previous h_lot updated.");
                    closeCons();
                    return true;
                } else {
                    Log.e("Error : ", "No lot found with this number.");
                    closeCons();
                    return false;
                }
            } catch (SQLException e) {
                error = e.getMessage();
                Log.e("Error :", error);
                closeCons();
                return false;
            }
     
        }

    Et enfin, la plus mastock de tous, la fonction d'INSERT :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
     
    public static boolean ADD_VALVE_ASSEMBLY_RESTOCK(String machineNumber, int iRestockPartType, String restockPartNumber, int iDirectPass, int iShift) {
            String h_lot_number_old = "";
            String sDirectPass = String.valueOf(iDirectPass);
            String sShift = String.valueOf(iShift);
            if (setUpConnexion("mainDB")) {
                try {
                    h_lot_number_old = LOAD_PREVIOUS_H_LOT_NUMBER(machineNumber);
                    PreparedStatement p = newTransact("INSERT INTO valve_assembly_h (\"machine_number\","
                            + " \"h_lot_number\", \"h_lot_number_old\", \"direct_pass\", \"shift\") VALUES ('"
                            + machineNumber + "', '" + restockPartNumber + "', '" + h_lot_number_old
                            + "', '" + sDirectPass + "', '" + sShift + "')", "mainDB");
                    int count = p.executeUpdate();
                    if (count > 0) {
                        Log.d("Success : ", count + " line(s) created. ");
                    } else {
                        Log.e("Error : ", "Unexpected result");
                    }
                    UPDATE_PREVIOUS_H_LOT_STATUT(h_lot_number_old);
                    closeCons();
                    return true;
                } catch (SQLException e) {
                    error = e.getMessage();
                    Log.e("Error :", error);
                    return false;
                }
            } else {
                Log.e("Error", "Impossible to set up the database connection."); // NE DEVRAIT
                return false;                                      // PAS ARRIVER SAUF SI LE WIFI TOMBE
            }
        }

    Edit : en complément, voici un petit screen d'une session "Debug" avec les variables debug
    Nom : Capture d’écran 2022-04-22 074334.png
Affichages : 244
Taille : 83,0 Ko


    À ceux qui sont encore là, merci pour votre lecture et votre temps accordé !

    Phae

  2. #2
    Membre émérite Avatar de vttman
    Homme Profil pro
    Développeur "couteau mosellan"
    Inscrit en
    Décembre 2002
    Messages
    1 140
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur "couteau mosellan"
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2002
    Messages : 1 140
    Points : 2 286
    Points
    2 286
    Par défaut
    Bonjour,

    Trop de " il me semble, pourquoi pas ceci ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
     
    PreparedStatement p = 
    newTransact(
    "INSERT INTO valve_assembly_h (machine_number, h_lot_number, h_lot_number_old, direct_pass, shift) "
    + "VALUES ('" + 
    machineNumber + 
    "', '" + 
    restockPartNumber + 
    "', '" + 
    h_lot_number_old + 
    "', '" + 
    sDirectPass + 
    "', '" + 
    sShift + 
    "')", 
    "mainDB");

    Et aussi se débrouiller pour afficher le contenu de cet insert avant exécution ...

    Bon ça fait une réponse, je retourne me prendre un café
    Emérite, émérite je ne pense pas ... plutôt dans le développement depuis FORT FORT longtemps, c'est mon job, ça oui
    A part ça ... Il ne pleut jamais en Moselle !

  3. #3
    Membre régulier
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Avril 2022
    Messages
    37
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Chef de projet NTIC
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2022
    Messages : 37
    Points : 79
    Points
    79
    Par défaut
    Citation Envoyé par vttman Voir le message
    Bonjour,

    Trop de " il me semble, pourquoi pas ceci ?



    Et aussi se débrouiller pour afficher le contenu de cet insert avant exécution ...

    Bon ça fait une réponse, je retourne me prendre un café
    Bnjour vttman, merci pour ta réponse. Et bon café ! j'ai oublié mon thermos ce matin personnellement... !!

    J'ai retiré tous les ", je m'étais calqué sur une requête effectuée depuis MSSMS.

    Pour répondre à afficher le contenu, voici ci dessous l'état des variables avant l'execution de "p.executeUpdate();"

    Nom : Capture d’écran 2022-04-22 074334.png
Affichages : 235
Taille : 119,2 Ko

    note : j'ai entretemps modifié une colonne, d'où les changements dans la requête

    Edit : détail de newTransact appelée lors de PreparedStatement p
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    public synchronized static PreparedStatement newTransact(String baseQuery, String DBname) throws SQLException {
            Connection connection;
            if (mainCon == null && exportCon == null) {
                setUpConnexion(DBname);
                connection = mainCon;
                if (DBname.equals("exportDB")) {
                    connection = exportCon;
                }
            } else if (exportCon != null) {
                connection = exportCon;
            } else {
                connection = mainCon;
            }
            PreparedStatement toReturn = (PreparedStatement) connection.prepareStatement(baseQuery);
            return toReturn;
        }
    J'espère que ces informations correspondent à ton attendu.

    Phae

  4. #4
    Expert confirmé
    Homme Profil pro
    Inscrit en
    Septembre 2006
    Messages
    2 937
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2006
    Messages : 2 937
    Points : 4 358
    Points
    4 358
    Par défaut
    C'est une mauvaise pratique de créer des requêtes SQL en concaténant des chaînes de caractères alors que le PreparedStatement de JDBC a toutes les fonctions pour passer correctement les paramètres en fonction de leur positionnement.
    (des frameworks de plus haut niveau offrent la possibilité d'utiliser des noms pour les paramètres)
    Non seulement cela ouvre la porte a toutes sortes d'erreurs, à l'injection SQL et en plus cela force le SGBD a ré-analyser (parsing) le query à chaque appel ce qui pénalise les performances,
    cela "tue" le concept même du PreparedStatement...

  5. #5
    Membre régulier
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Avril 2022
    Messages
    37
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Chef de projet NTIC
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2022
    Messages : 37
    Points : 79
    Points
    79
    Par défaut
    Citation Envoyé par JeitEmgie Voir le message
    C'est une mauvaise pratique de créer des requêtes SQL en concaténant des chaînes de caractères alors que le PreparedStatement de JDBC a toutes les fonctions pour passer correctement les paramètres en fonction de leur positionnement.
    (des frameworks de plus haut niveau offrent la possibilité d'utiliser des noms pour les paramètres)
    Non seulement cela ouvre la porte a toutes sortes d'erreurs, à l'injection SQL et en plus cela force le SGBD a ré-analyser (parsing) le query à chaque appel ce qui pénalise les performances,
    cela "tue" le concept même du PreparedStatement...
    Entendu, je suis encore un bébou SQLeur, je connais pas encore les eusses et coutumes

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
          String baseQuery = "INSERT INTO valve_assembly_h (machine_number, h_lot_number, previous_restock_id, direct_pass, shift) VALUES (?, ?, ?, ?, ?)";
                    PreparedStatement p = newTransact(baseQuery, "mainDB");
                    p.setString(1, machineNumber);
                    p.setString(2, restockPartNumber);
                    p.setString(3, h_lot_number_old);
                    p.setInt(4, iDirectPass);
                    p.setInt(5, iShift);
    Comme ceci ?

    Edit : Tiens, p devrait être différent au moment de l'execution, non ?
    Nom : Capture d’écran 2022-04-22 074334.png
Affichages : 227
Taille : 119,2 Ko

  6. #6
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 551
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    Hello,

    effectivement éviter les SQL injections c'est important, d'où le bon usage de PreparedStatement.

    Mais concernant le problème remonté : c'est quand même complètement typique de l'absence de commit de la connexion, or, de commit, je n'en vois pas dans le code présenté... Ce ne serait pas simplement ça ?

    Et sinon :

    Mon application est connectée à l'aide de JTDS & jdbc à une base de données MS SQL Server.(On partira du principe que la connexion en direct à la DB, c'est OK ! )
    Ouais ben, OK ça l'est pas. Il y a juste aucun doute là-dessus. On va dire que c'est juste pour programmer un jouet dont tu seras le seul à te servir, mais dans ce cas c'est peut-être pas obligé de s'arracher les cheveux...
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  7. #7
    Membre régulier
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Avril 2022
    Messages
    37
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Chef de projet NTIC
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2022
    Messages : 37
    Points : 79
    Points
    79
    Par défaut
    Citation Envoyé par thelvin Voir le message
    Hello,

    effectivement éviter les SQL injections c'est important, d'où le bon usage de PreparedStatement.

    Mais concernant le problème remonté : c'est quand même complètement typique de l'absence de commit de la connexion, or, de commit, je n'en vois pas dans le code présenté... Ce ne serait pas simplement ça ?

    Et sinon :



    Ouais ben, OK ça l'est pas. Il y a juste aucun doute là-dessus. On va dire que c'est juste pour programmer un jouet dont tu seras le seul à te servir, mais dans ce cas c'est peut-être pas obligé de s'arracher les cheveux...
    Ahaaaaaah, ahahahah... Un commit() tu dis ? Connais pas On va regarder tout ça de plus près, hein !

    Concernant la deuxième partie de ta réponse, on est totalement d'accord que c'est pas OK, par contre c'est ni un jouet, ni fait pour être publié sur un store. Donc, on part du principe que exceptionnellement, c'est OK.
    Un peu comme quand en physique au lycée ont déclare que la masse des électrons et nulle... On sait que c'est faux, maaaaaais, là, dans cette sitution, elle est nulle


    Edit : Thelvin, sauveur de beaucoup d'autres, et maintenant mon sauveur Il manquait effectivement un commit() !! Purée, tellement d'heures perdues pour un pauvre mot manquant...

  8. #8
    Membre émérite Avatar de vttman
    Homme Profil pro
    Développeur "couteau mosellan"
    Inscrit en
    Décembre 2002
    Messages
    1 140
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur "couteau mosellan"
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2002
    Messages : 1 140
    Points : 2 286
    Points
    2 286
    Par défaut
    Citation Envoyé par thelvin Voir le message
    Hello,

    effectivement éviter les SQL injections c'est important, d'où le bon usage de PreparedStatement.

    Mais concernant le problème remonté : c'est quand même complètement typique de l'absence de commit de la connexion, or, de commit, je n'en vois pas dans le code présenté... Ce ne serait pas simplement ça ?
    Ah Super ! j'y avais bien pensé ... mais je m'étais imaginé un commit implicite ...
    Emérite, émérite je ne pense pas ... plutôt dans le développement depuis FORT FORT longtemps, c'est mon job, ça oui
    A part ça ... Il ne pleut jamais en Moselle !

  9. #9
    Membre régulier
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Avril 2022
    Messages
    37
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Chef de projet NTIC
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2022
    Messages : 37
    Points : 79
    Points
    79
    Par défaut Résolution du problème
    Pour résolution du problème expliqué dans mon premier message, ci dessous les modifications effectuées :

    Modification de closeCons() pour ajouter la fonction de commit si nécessaire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
     
    public synchronized static void closeCons() {
            try {
                if (needCommit) {
                    commitTransacts();
                }
                if (exportCon != null) {
                    exportCon.close();
                }
                mainCon.close();
            } catch (Exception e) {
                Log.e("Error : ", "Erreur a la fermeture des connexions SQL:" + e.getMessage());
            }
        }
        public synchronized static void commitTransacts() {
            try {
                if(exportCon != null) {
                    exportCon.commit();
                }
                mainCon.commit();
            } catch (SQLException e) {
                Log.e("Error : ", "Erreur lors du commit : " + e.getMessage());
            }
        }
    et ajoute de avant d'appeler mon closeCons() dans ma fonction globale (ADD_VALVE_ASSEMBLY_RESTOCK)


    Merci pour votre participation et vos réponses

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 1
    Dernier message: 27/10/2019, 23h58
  2. Réponses: 0
    Dernier message: 03/07/2014, 17h09
  3. Remplir table sql server depuis une table excel
    Par silifana dans le forum MS SQL Server
    Réponses: 5
    Dernier message: 14/02/2009, 15h23
  4. déployer sql server avec une application?
    Par badge2033 dans le forum Général Dotnet
    Réponses: 2
    Dernier message: 02/07/2008, 09h15
  5. Connecté une base de donnée sql server v7 à une application Jbuilder9
    Par souheilzouabizouabi dans le forum MS SQL Server
    Réponses: 0
    Dernier message: 15/04/2008, 12h31

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo