2009-08-20 14 views
27

Ho una lista di nomi per es .:Come impostare l'elenco dei parametri sull'istruzione preparata?

List<String> names = ... 
names.add('charles'); 
... 

e una dichiarazione:

PreparedStatement stmt = 
    conn.prepareStatement('select * from person where name in (?)'); 

come effettuare le seguenti operazioni:

stmt.setParameterList(1,names); 

C'è una soluzione? qualcuno può spiegare perché questo metodo è mancante?

utilizzando: Java, PostgreSQL, jdbc3

+0

Eventuali duplicati di [PreparedStatement IN clausola alternative?] (http://stackoverflow.com/questions/178479/preparedstatement-in-clause-alternatives) – luator

risposta

17

Non c'è un modo pulito di fare questo semplicemente impostando un elenco sul PreparedStatement che io sappia.

Scrive il codice che costruisce l'istruzione SQL (o sostituisce meglio un singolo? O un token simile) con il numero appropriato di punti interrogativi (lo stesso numero dell'elenco) e quindi itera sull'elenco impostando il parametro per ciascuno.

1

questo metodo non è presente a causa della cancellazione del tipo durante il runtime il tipo di parametro dell'elenco viene perso. Pertanto la necessità di aggiungere diversi metodi arires: setIntParameters, setLongParameters, setObjectParameters, ecc

+0

se esiste un metodo di aggiunta per ogni tipo di dati, perché non esiste un metodo "addList" per anche ogni tipo di dati? (Es addStringList (...)) – Chris

+0

questo è il punto, l'interfaccia affermazione è già gonfio anche senza contare elenco varianti – dfa

+2

Type cancellazione non è una buona ragione, ci potrebbero essere setArrayParameter (int pos, Object [] params) – ycnix

2

Per postgres 9 Ho usato questo approccio:

jdbcTemplate.query(getEmployeeReport(), new PreparedStatementSetter() { 
     @Override 
     public void setValues(PreparedStatement ps) throws SQLException { 
      ps.setTimestamp(1, new java.sql.Timestamp(from.getTime())); 
      ps.setTimestamp(2, new java.sql.Timestamp(to.getTime())); 
      StringBuilder ids = new StringBuilder(); 
      for (int i = 0; i < branchIds.length; i++) { 
       ids.append(branchIds[i]); 
       if (i < branchIds.length - 1) { 
        ids.append(","); 
       } 
      } 
      // third param is inside IN clause 
      // Use Types.OTHER avoid type check while executing query 
      ps.setObject(3, ids.toString(), **Types.OTHER**); 
     } 
    }, new PersonalReportMapper()); 
+0

Funziona davvero per 'in (?)'? Che aspetto ha l'affermazione vera una volta che viene rilasciata al server? – rbellamy

+0

Si desidera evitare la concatenazione di valori stringa nel codice JDBC, poiché ciò potrebbe facilmente portare a errori di SQL injection. -1 –

-1

stavo rivedendo il codice di questa mattina e uno dei miei colleghi aveva un diverso approccio, basta passare il parametro usando setString("name1','name2','name3").

Nota: Ho saltato la virgoletta singola all'inizio e alla fine perché verranno aggiunti dallo setString.

+1

Per stringhe costanti, potrebbe essere accettabile. Per l'input dell'utente, è un bell'esempio di codice vulnerabile all'iniezione SQL. –

+0

Questo assolutamente non dovrebbe funzionare. Se lo fa, c'è un bug nel tuo driver JDBC. 'setString' si occupa degli apostrofi, in modo da ottenere effettivamente il' String' che hai passato. Il tuo collega ha testato il suo codice? –

18

Questa domanda è molto vecchio, ma nessuno ha suggerito di usare setArray

Questa risposta potrebbe aiutare https://stackoverflow.com/a/10240302/573057

+2

setArray non funziona con MySQL o JavaDB poiché non supportano il tipo di dati ARRAY in SQL. Vedere la nota nella parte superiore di: https://docs.oracle.com/javase/tutorial/jdbc/basics/array.html – TigerC10

+0

@ TigerC10 buon punto ... curiosità piqued re: Java in-memory dB - Derby (JavaDB) non supporta ma entrambi [h2] (http://www.h2database.com/html/datatypes.html#array_type) e [hsqldb] (http://hsqldb.org/doc/guide/sqlgeneral- chapt .html # sgc_array) do. – earcam

-2

altro metodo:

public void setValues(PreparedStatement ps) throws SQLException { 
    // first param inside IN clause with myList values 
    ps.setObject(1 , myList.toArray(), 2003); // 2003=array in java.sql.Types 
} 
+1

Si prega di dare qualche spiegazione al tuo codice – eliasah

+0

funziona davvero? – wutzebaer

-1

Dopo aver esaminato diverse soluzioni in diversi forum e non trovando un buona soluzione, sento che il trucco sottostante che ho trovato è il più facile da seguire e codificare. Si noti tuttavia che ciò non utilizza la query preparata ma ottiene comunque il lavoro svolto:

Esempio: si supponga di avere un elenco di parametri da passare nella clausola 'IN'. Basta inserire una stringa fittizia all'interno della clausola 'IN', diciamo, "PARAM" non denota l'elenco dei parametri che verranno immessi al posto di questa stringa fittizia.

select * from TABLE_A where ATTR IN (PARAM); 

È possibile raccogliere tutti i parametri in una singola variabile String nel codice Java. Questo può essere fatto nel modo seguente:

String param1 = "X"; 
    String param2 = "Y"; 
    String param1 = param1.append(",").append(param2); 

È possibile aggiungere tutti i parametri separati da virgole in una singola variabile stringa, 'param1', nel nostro caso.

Dopo aver raccolto tutti i parametri in una stringa singola, è sufficiente sostituire il testo fittizio nella query, ad esempio "PARAM" in questo caso, con il parametro String, cioè param1. Ecco cosa è necessario fare:

String query = query.replaceFirst("PARAM",param1); where we have the value of query as 

    query = "select * from TABLE_A where ATTR IN (PARAM)"; 

Ora è possibile eseguire la query utilizzando il metodo executeQuery(). Assicurati di non avere la parola "PARAM" nella tua query ovunque. Puoi usare una combinazione di caratteri speciali e alfabeti invece della parola "PARAM" per assicurarti che non ci sia alcuna possibilità che una parola di questo tipo arrivi nella query. Spero tu abbia la soluzione.

+0

Sapete che questo potrebbe portare a iniezioni SQL? –

+0

Grazie funziona ... :) –

0

Nel caso in cui le domande significato è quello di impostare diversi parametri in una singola chiamata ...

Perché la convalida del tipo è già definita in un livello più alto, credo che l'unica necessità è per setObject(...).

Così, un metodo di utilità può essere utilizzato:

public static void addParams(PreparedStatement preparedStatement, Object... params) throws SQLException { 
    for (int i = 0; i < params.length; i++) { 
     Object param = params[i]; 
     preparedStatement.setObject(i+1, param); 
    } 
} 

Usage:

SqlUtils.addParams(preparedStatement, 1, '2', 3d); 

Sentitevi liberi di conversione a un Java 8 lambda :)

+0

setObject che passa una lista genera un'eccezione con il driver Oracle –

Problemi correlati