2009-01-07 10 views
4

Je prévois de remplacer à plusieurs reprises les objets Statement exécutés par des objets PreparedStatement pour améliorer les performances. J'utilise des arguments comme la fonction MySQL now(), et les variables de chaîne.Comment fonctionne PreparedStatement de Java?

La plupart des requêtes PreparedStatement j'ai vu contenues des valeurs constantes (comme 10, et des chaînes comme "New York") comme arguments utilisés pour la ? dans les requêtes. Comment pourrais-je utiliser des fonctions comme now() et des variables comme arguments? Est-il nécessaire d'utiliser les ? dans les requêtes au lieu des valeurs réelles? Je suis assez confus.

+0

Demandez-vous si vous pouvez utiliser un Fonction de chaîne de caractères à la place d'un littéral de chaîne? Demandez-vous si vous pouvez utiliser une fonction int-value à la place d'un entier littéral? Pouvez-vous fournir un extrait de code? –

Répondre

8

Si vous avez des variables, utilisez le '?'

int temp = 75; 
PreparedStatement pstmt = con.prepareStatement(
    "UPDATE test SET num = ?, due = now() "); 
pstmt.setInt(1, temp); 
pstmt.executeUpdate(): 

produit une sql statment qui ressemble à:

UPDATE test SET num = 75, due = now(); 
10

Si vous avez une variable qui vient de l'entrée de l'utilisateur, il est essentiel que vous utilisez? plutôt que de concaténer les chaînes. Les utilisateurs peuvent entrer une chaîne de manière malveillante, et si vous déposez la chaîne directement dans SQL, elle peut exécuter une commande que vous n'aviez pas prévue.

Je me rends compte celui-ci est galvaudé, mais il dit parfaitement:

Little Bobby Tables

+2

Je crois, vous voulez dire injections SQL. –

0

Vous ne devez pas utiliser des espaces réservés dans un PreparedStatement. Quelque chose comme:

PreparedStatement stmt = con.prepareStatement("select sysdate from dual"); 

fonctionnerait très bien. Cependant, vous ne pouvez pas utiliser un espace réservé, puis lui lier un appel de fonction. Quelque chose comme cela ne peut pas être utilisé pour appeler la fonction sysdate:

PreparedStatement stmt = con.prepareStatement("select ? from dual"); 
stmt.setSomethingOrOther(1, "sysdate"); 
0

Si vous appelez les fonctions intégrées de votre serveur SQL puis utilisez PreparedStatement. Si vous appelez des procédures stockées qui ont été chargées sur votre serveur SQL, utilisez CallableStatement.

Utilisez les points d'interrogation comme espaces réservés pour les paramètres de fonction/procédure que vous transmettez et les valeurs de retour de fonction que vous recevez.

0

J'ai développé une fonction qui vous permet d'utiliser des paramètres nommés dans vos requêtes SQL:

private PreparedStatement generatePreparedStatement(String query, Map<String, Object> parameters) throws DatabaseException 
    { 
     String paramKey = ""; 
     Object paramValue = null; 
     PreparedStatement statement = null; 
     Pattern paramRegex = null; 
     Matcher paramMatcher = null; 
     int paramIndex = 1; 

     try 
     { 
      //Create the condition 
      paramRegex = Pattern.compile("(:[\\d\\w_-]+)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); 
      paramMatcher = paramRegex.matcher(query); 
      statement = this.m_Connection.prepareStatement(paramMatcher.replaceAll("?"), 
           ResultSet.TYPE_FORWARD_ONLY, 
           ResultSet.CONCUR_READ_ONLY, 
           ResultSet.HOLD_CURSORS_OVER_COMMIT); 

      //Check if there are parameters 
      paramMatcher = paramRegex.matcher(query); 
      while (paramMatcher.find()) 
      { 
       paramKey = paramMatcher.group().substring(1); 
       if(parameters != null && parameters.containsKey(paramKey)) 
       { 
        //Add the parameter 
        paramValue = parameters.get(paramKey); 
        if (paramValue instanceof Date) 
        { 
         statement.setDate(paramIndex, (java.sql.Date)paramValue);     
        } 
        else if (paramValue instanceof Double) 
        { 
         statement.setDouble(paramIndex, (Double)paramValue);     
        } 
        else if (paramValue instanceof Long) 
        { 
         statement.setLong(paramIndex, (Long)paramValue);     
        } 
        else if (paramValue instanceof Integer) 
        { 
         statement.setInt(paramIndex, (Integer)paramValue);     
        } 
        else if (paramValue instanceof Boolean) 
        { 
         statement.setBoolean(paramIndex, (Boolean)paramValue);     
        } 
        else 
        { 
         statement.setString(paramIndex, paramValue.toString());  
        } 
       } 
       else 
       { 
        throw new DatabaseException("The parameter '" + paramKey + "' doesn't exists in the filter '" + query + "'"); 
       } 

       paramIndex++; 
      } 
     } 
     catch (SQLException l_ex) 
     { 
      throw new DatabaseException(tag.lib.common.ExceptionUtils.getFullMessage(l_ex)); 
     } 

     return statement; 
    } 

Vous pouvez l'utiliser de cette façon:

Map<String, Object> pars = new HashMap<>(); 
pars.put("name", "O'Really"); 
String sql = "SELECT * FROM TABLE WHERE NAME = :name"; 
Questions connexes