2015-10-20 31 views
7

Tôi đang cố gắng thực hiện truy vấn IN bằng cách sử dụng MYSQL JDBI trên Dropwizard (không liên quan, tôi giả định).Làm cách nào để sử dụng toán tử IN với JDBI?

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

Như đã đề cập here, tôi cũng đã chú thích các lớp học với

@UseStringTemplate3StatementLocator 

Nhưng khi tôi bắt đầu ứng dụng, tôi nhận được lỗi sau:

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

Có ai có ý tưởng hay về cách giải quyết vấn đề này?

Trả lời

5

Có hai cách để đạt được điều đó.

. Sử dụng UseStringTemplate3StatementLocator

chú thích này hy vọng Group Files với câu lệnh SQL trong StringTemplate

Nói rằng tôi có tập tin này PersonExternalizedSqlDAO

// PersonExternalizedSqlDAO.java 

package com.daoexp.dao; 

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

Vì chúng ta đang sử dụng UseStringTemplate3StatementLocator chúng ta phải tạo *.sql.stg file trong đường dẫn cùng lớp. Đối với ví dụ: trong resources/com/daoexp/dao/PersonExternalizedSqlDAO.sql.stg

group PersonExternalizedSqlDAO; 

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

Bây giờ bạn sẽ có thể truy vấn mà không cần bất kỳ vấn đề.


. Cách tiếp cận khác là sử dụng ArgumentFactory xử lý loại dữ liệu tùy chỉnh của bạn (trong trường hợp này là Danh sách) cho JDBI với @Bind. Đây là cách tiếp cận thích hợp nhất.

Vì vậy, tạo này nhà máy luận danh sách

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

gì lớp này không?

  • chấp nhận trường hợp của Danh sách
  • chuyển đổi danh sách số nguyên/chuỗi mảng và liên kết với tuyên bố sẵn sàng

Hãy chắc chắn rằng bạn đăng ký nhà máy lập luận này với ví dụ DBI của bạn.

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

Bây giờ bạn sẽ có thể truy vấn sử dụng List theo cách đơn giản hơn (nghĩa là), bạn phải sử dụng @Bind. Đó là nó.

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

Tham khảo:

Thông tin bổ sung:

// 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; 
    } 
} 
+1

Có vẻ như tôi không thể sử dụng phương pháp hai do cơ sở dữ liệu SQL của tôi là MySQL. nơi các kiểu mảng không được hỗ trợ (createArrayOf). Tôi đã sử dụng phương thức đầu tiên của bạn bằng tệp sql.stg. Cảm ơn nhiều! Và btw, ExternalizedSqlViaStringTemplate3 không được dùng nữa, sử dụng UseStringTemplate3StatementLocator. – Kenneth

+0

Tôi nhận ngoại lệ trong giải pháp 1 là, gây ra: org.skife.jdbi.v2.exceptions.UnableToExecuteStatementException: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Bạn có lỗi trong cú pháp SQL của mình; kiểm tra hướng dẫn tương ứng với phiên bản máy chủ MySQL của bạn cho cú pháp đúng để sử dụng gần 'getPersonByNames' ở dòng 1, tôi nghĩ rằng chuỗi sql không được thay thế. – dkb

+0

Dường như phương thức hai cũng không được hỗ trợ trong Oracle: 'Gây ra bởi: java.sql.SQLException: Tính năng không được hỗ trợ tại oracle.jdbc.driver.PhysicalConnection.createArrayOf (PhysicalConnection.java:9283)' –

9

Tôi nghĩ, bạn sử dụng số StringTemplate 4. Bạn cần sử dụng StringTemplate 3 thay vì StringTemplate 4. Thêm phụ thuộc này :

<dependency> 
    <groupId>org.antlr</groupId> 
    <artifactId>stringtemplate</artifactId> 
    <version>3.2.1</version> 
</dependency> 
+0

Sẽ kiểm tra sau ngày hôm nay, nhưng trong mã tôi dán nó nói phiên bản 3? "UseStringTemplate3StatementLocator" – Kenneth

+1

Cảm ơn, nếu tôi không thêm sự phụ thuộc này, ứng dụng Dropwizard của tôi không thể bắt đầu bằng một 'AnnotationFormatError':' Invalid default: public abstract java.lang.Class org.skife.jdbi.v2.sqlobject.stringtemplate.UseStringTemplate3StatementLocator .errorListener() '. – Radu

Các vấn đề liên quan