10

我正在尝试在 Dropwizard 上使用 MYSQL JDBI 进行 IN 查询(​​我认为不相关)。

@SqlQuery("SELECT id FROM table where field in (<list>)")
List<Integer> findSomething(@BindIn("list") List<String> 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()

有没有人知道如何解决这个问题?

4

2 回答 2

14

我认为,您使用StringTemplate 4. 您需要使用StringTemplate 3而不是StringTemplate 4. 添加此依赖项

<dependency>
    <groupId>org.antlr</groupId>
    <artifactId>stringtemplate</artifactId>
    <version>3.2.1</version>
</dependency>
于 2015-10-21T00:37:29.327 回答
8

有两种方法可以实现它。

1 . 使用UseStringTemplate3StatementLocator

此注释需要在StringTemplate中使用 SQL 语句的Group Files

假设我有这个文件 PersonExternalizedSqlDAO

// PersonExternalizedSqlDAO.java

package com.daoexp.dao;

@@ExternalizedSqlViaStringTemplate3
@RegisterMapper(PersonMapper.class)
public interface PersonExternalizedSqlDAO {
    @SqlQuery
    List<Person> getPersonByNames(@BindIn("names") List<String> names);
}

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

group PersonExternalizedSqlDAO;

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

现在您应该可以毫无问题地进行查询了。


2 . 另一种方法是使用ArgumentFactory为 JDBI 处理您的自定义数据类型(在本例中为列表)@Bind。这是最可取的方法。

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

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);
            }
        };
    }
}

这门课是做什么的?

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

确保使用 DBI 实例注册此参数工厂。

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

现在您应该能够以List更简单的方式查询 using(即)您必须使用@Bind. 就是这样。

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

参考:

附加信息:

// 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;
    }
}
于 2015-10-26T16:36:50.817 回答