JDBI 如何使用 IN 运算符?
How to use IN operator with JDBI?
我正在尝试在 Dropwizard 上使用 MYSQL JDBI 进行 IN 查询(我认为不相关)。
@SqlQuery("SELECT id FROM table where field in (<list>)")
List<Integer> findSomething(@BindIn("list") List<String> someList);
按照建议 here,我还用
注释了 class
@UseStringTemplate3StatementLocator
但是当我启动应用程序时,出现以下错误:
Exception in thread "main" java.lang.annotation.AnnotationFormatError: Invalid default: public abstract java.lang.Class org.skife.jdbi.v2.sqlobject.stringtemplate.UseStringTemplate3StatementLocator.errorListener()
有人知道如何解决这个问题吗?
我想,你用的StringTemplate 4
。
您需要使用 StringTemplate 3
而不是 StringTemplate 4
。添加此 依赖关系 :
<dependency>
<groupId>org.antlr</groupId>
<artifactId>stringtemplate</artifactId>
<version>3.2.1</version>
</dependency>
有两种方法可以实现。
1。使用 UseStringTemplate3StatementLocator
此注释需要 Group Files with SQL statement in StringTemplate
假设我有这个文件 PersonExternalizedSqlDAO
// PersonExternalizedSqlDAO.java
package com.daoexp.dao;
@@ExternalizedSqlViaStringTemplate3
@RegisterMapper(PersonMapper.class)
public interface PersonExternalizedSqlDAO {
@SqlQuery
List<Person> getPersonByNames(@BindIn("names") List<String> names);
}
由于我们正在使用 UseStringTemplate3StatementLocator
,因此我们必须在相同的 class 路径中创建 *.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);
}
};
}
}
这个 class 有什么作用?
- 接受列表实例
- 将integer/string列表转换为数组并与准备好的语句绑定
确保在 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<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;
}
}
我正在尝试在 Dropwizard 上使用 MYSQL JDBI 进行 IN 查询(我认为不相关)。
@SqlQuery("SELECT id FROM table where field in (<list>)")
List<Integer> findSomething(@BindIn("list") List<String> someList);
按照建议 here,我还用
注释了 class@UseStringTemplate3StatementLocator
但是当我启动应用程序时,出现以下错误:
Exception in thread "main" java.lang.annotation.AnnotationFormatError: Invalid default: public abstract java.lang.Class org.skife.jdbi.v2.sqlobject.stringtemplate.UseStringTemplate3StatementLocator.errorListener()
有人知道如何解决这个问题吗?
我想,你用的StringTemplate 4
。
您需要使用 StringTemplate 3
而不是 StringTemplate 4
。添加此 依赖关系 :
<dependency>
<groupId>org.antlr</groupId>
<artifactId>stringtemplate</artifactId>
<version>3.2.1</version>
</dependency>
有两种方法可以实现。
1。使用 UseStringTemplate3StatementLocator
此注释需要 Group Files with SQL statement in StringTemplate
假设我有这个文件 PersonExternalizedSqlDAO
// PersonExternalizedSqlDAO.java
package com.daoexp.dao;
@@ExternalizedSqlViaStringTemplate3
@RegisterMapper(PersonMapper.class)
public interface PersonExternalizedSqlDAO {
@SqlQuery
List<Person> getPersonByNames(@BindIn("names") List<String> names);
}
由于我们正在使用 UseStringTemplate3StatementLocator
,因此我们必须在相同的 class 路径中创建 *.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);
}
};
}
}
这个 class 有什么作用?
- 接受列表实例
- 将integer/string列表转换为数组并与准备好的语句绑定
确保在 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<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;
}
}