Ci sono due modi per realizzarla.
. Utilizzando UseStringTemplate3StatementLocator
Questa annotazione si aspetta Group Files con istruzione SQL in StringTemplate
Dire che ho questo file PersonExternalizedSqlDAO
// PersonExternalizedSqlDAO.java
package com.daoexp.dao;
@@ExternalizedSqlViaStringTemplate3
@RegisterMapper(PersonMapper.class)
public interface PersonExternalizedSqlDAO {
@SqlQuery
List<Person> getPersonByNames(@BindIn("names") List<String> names);
}
Dal momento che stiamo usando UseStringTemplate3StatementLocator
dobbiamo creare *.sql.stg
file nella stessa strada di classe. Per esempio: in resources/com/daoexp/dao/PersonExternalizedSqlDAO.sql.stg
group PersonExternalizedSqlDAO;
getPersonByNames(names) ::= <<
select * from person where name in (<names>)
>>
Ora si dovrebbe essere in grado di interrogare senza problemi.
. Un altro approccio è quello di utilizzare ArgumentFactory
che gestisce il tipo di dati personalizzati (in questo caso Elenco) per JDBI con @Bind
. Questo è l'approccio più preferibile.
Quindi creare questa lista di argomenti fabbrica
public class ListArgumentFactory implements ArgumentFactory<List> {
@Override
public boolean accepts(Class<?> expectedType, Object value, StatementContext ctx) {
return value instanceof List;
}
@Override
public Argument build(Class<?> expectedType, final List value, StatementContext ctx) {
return new Argument() {
@Override
public void apply(int position, PreparedStatement statement, StatementContext ctx) throws SQLException {
String type = null;
if(value.get(0).getClass() == String.class){
type = "varchar";
} else if(value.get(0).getClass() == Integer.class){
// For integer and so on...
} else {
// throw error.. type not handled
}
Array array = ctx.getConnection().createArrayOf(type, value.toArray());
statement.setArray(position, array);
}
};
}
}
Cosa questa classe fa?
- accetta istanza di Lista
- convertire l'elenco intero/stringa in array e si lega con istruzione preparata
Assicurarsi di registrare questa fabbrica discussione con l'istanza DBI.
final DBIFactory factory = new DBIFactory();
final DBI jdbi = factory.build(environment, configuration.getDataSourceFactory(), "h2");
jdbi.registerArgumentFactory(new ListArgumentFactory());
Ora si dovrebbe essere in grado di interrogare utilizzando List
in modo più semplice (cioè) si deve utilizzare @Bind
. Questo è tutto.
@RegisterMapper(PersonMapper.class)
public interface PersonDAO {
@SqlQuery("select * from person where name = any(:names)")
List<Person> getPersonByNames(@Bind("names") List<String> names);
}
consultare:
Informazione supplementare:
// PersonMapper.java
public class PersonMapper implements ResultSetMapper<Person> {
public Person map(int index, ResultSet r, StatementContext ctx) throws SQLException {
Person person = new Person();
person.setId(r.getInt("id"));
person.setName(r.getString("name"));
return person;
}
}
Sembra che non posso usare il metodo due a causa del mio database SQL che è MySQL. dove i tipi di array non sono supportati (createArrayOf). L'ho fatto usando il tuo primo metodo, con il file sql.stg. Grazie mille! E btw, ExternalizedSqlViaStringTemplate3 è deprecato, usa UseStringTemplate3StatementLocator. – Kenneth
Ricevo un'eccezione nella soluzione 1 come causa: org.skife.jdbi.v2.exceptions.UnableToExecuteStatementException: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: si è verificato un errore nella sintassi SQL; controlla il manuale che corrisponde alla tua versione del server MySQL per la sintassi corretta da usare vicino a 'getPersonByNames' alla riga 1, penso che la stringa di sql non venga sostituita. – dkb
Sembra che anche il metodo due non sia supportato in Oracle: 'Causato da: java.sql.SQLException: funzione non supportata su oracle.jdbc.driver.PhysicalConnection.createArrayOf (PhysicalConnection.java:9283)' –