如何在JDBI中使用IN运算符?

我正在尝试使用Dropwizard上的MYSQL JDBI进行IN查询(不相关,我假设)。

@SqlQuery("SELECT id FROM table where field in ()") List findSomething(@BindIn("list") List someList); 

正如这里所建议的那样,我也用类别注释了这个类

 @UseStringTemplate3StatementLocator 

但是当我启动应用程序时,我收到以下错误:

 Exception in thread "main" java.lang.annotation.AnnotationFormatError: Invalid default: public abstract java.lang.Class org.skife.jdbi.v2.sqlobject.stringtemplate.UseStringTemplate3StatementLocator.errorListener() 

有没有人对如何解决这个问题有个好主意?

有两种方法可以实现它。

1 。 使用UseStringTemplate3StatementLocator

此批注要求StringTemplate中的 Group Files with SQL语句

说我有这个文件PersonExternalizedSqlDAO

 // PersonExternalizedSqlDAO.java package com.daoexp.dao; @@ExternalizedSqlViaStringTemplate3 @RegisterMapper(PersonMapper.class) public interface PersonExternalizedSqlDAO { @SqlQuery List getPersonByNames(@BindIn("names") List names); } 

由于我们使用的是UseStringTemplate3StatementLocator我们必须在同一个类路径中创建*.sql.stg文件。 例如:resources/com/daoexp/dao/PersonExternalizedSqlDAO.sql.stg

 group PersonExternalizedSqlDAO; getPersonByNames(names) ::= << select * from person where name in () >> 

现在您应该可以查询而不会出现任何问题。


2 。 另一种方法是使用ArgumentFactory来处理带有@Bind自定义数据类型(在本例中为List)。 这是最优选的方法。

所以创建这个列表参数工厂

 public class ListArgumentFactory implements ArgumentFactory { @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); } }; } } 

这堂课做什么?

  • 接受List的实例
  • 将整数/字符串列表转换为数组并使用预准备语句绑定

确保将此参数factory注册到DBI实例。

 final DBIFactory factory = new DBIFactory(); final DBI jdbi = factory.build(environment, configuration.getDataSourceFactory(), "h2"); jdbi.registerArgumentFactory(new ListArgumentFactory()); 

现在您应该能够以更简单的方式使用List进行查询(即)必须使用@Bind 。 而已。

 @RegisterMapper(PersonMapper.class) public interface PersonDAO { @SqlQuery("select * from person where name = any(:names)") List getPersonByNames(@Bind("names") List names); } 

参考:

  • jdbi doc

附加信息:

 // PersonMapper.java public class PersonMapper implements ResultSetMapper { 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; } } 

我想,你使用StringTemplate 4 。 您需要使用StringTemplate 3而不是StringTemplate 4 。 添加此依赖项

  org.antlr stringtemplate 3.2.1