Spring의 JDBCTemplate을 사용하여 IN () SQL 쿼리를 효과적으로 실행하는 방법은 무엇입니까?


177

Spring의 JDBCTemplate을 사용하여 IN () 쿼리를 수행하는보다 우아한 방법이 있는지 궁금합니다. 현재 나는 그런 식으로합니다 :

StringBuilder jobTypeInClauseBuilder = new StringBuilder();
for(int i = 0; i < jobTypes.length; i++) {
    Type jobType = jobTypes[i];

    if(i != 0) {
        jobTypeInClauseBuilder.append(',');
    }

    jobTypeInClauseBuilder.append(jobType.convert());
}

IN () 쿼리에 대한 절을 작성하기 위해 9 줄이 있으면 상당히 고통 스럽습니다. 준비된 문장의 매개 변수 대체와 같은 것을 원합니다.

답변:


275

매개 변수 소스를 원합니다.

Set<Integer> ids = ...;

MapSqlParameterSource parameters = new MapSqlParameterSource();
parameters.addValue("ids", ids);

List<Foo> foo = getJdbcTemplate().query("SELECT * FROM foo WHERE a IN (:ids)",
     parameters, getRowMapper());

이것은 getJdbcTemplate()유형의 인스턴스를 반환하는 경우에만 작동합니다NamedParameterJdbcTemplate


5
완벽하게, NamedParameterJdbcTemplate은 내가 찾던 것입니다. 또한 나는 모든 곳에서 물음표보다 명명 된 매개 변수를 좋아합니다. 고마워요!
Malax

5
작은 목록에서는 작동하지만 큰 목록에서 사용하려고하면 : ids가 "?,?,?,?,? ......"로 바뀌고 충분한 목록 항목이있는 쿼리가 발생합니다. 큰 목록에 적합한 솔루션이 있습니까?
nsayer

값을 임시 테이블에 삽입하고을 사용하여 조건을 작성해야 WHERE NOT EXISTS (SELECT ...)합니다.
하품

6
답을 완성하려면 : Spring 3.1 Reference — IN 절의 값 목록 전달 . 그러나 참고로 아무 말도하지 않았습니다 : 모든 Collection을 전달할 수 있습니다 .
Timofey Gorshkov

9
이상하게도 이것을 시도하면 "오류 코드 [17004]; 잘못된 열 유형"이 나타납니다.
Trevor

61

스프링 jdbc를 사용하여 "in clause"쿼리를 다음과 같이 수행합니다.

String sql = "SELECT bg.goodsid FROM beiker_goods bg WHERE bg.goodsid IN (:goodsid)";

List ids = Arrays.asList(new Integer[]{12496,12497,12498,12499});
Map<String, List> paramMap = Collections.singletonMap("goodsid", ids);
NamedParameterJdbcTemplate template = 
    new NamedParameterJdbcTemplate(getJdbcTemplate().getDataSource());

List<Long> list = template.queryForList(sql, paramMap, Long.class);

10
당신은 거의 3 살짜리 질문에 대한 답변을 수락 된 답변과 동일한 해결책으로 게시했습니다. 이것 뒤에 좋은 이유가 있습니까? :-)
Malax

16
이 답변은이 API에 NamedParameterJdbcTemplate이 필요하다는 것을 보여 주므로 더 명확합니다. 따라서 추가 세부 정보 janwen
IcedDante

@janwen, 솔루션 주셔서 감사합니다 !!! 내 요구 사항에 따라 제대로 작동합니다!
Karthik Amarnath Saakre

19

다음에 대한 예외가 발생하는 경우 : 유효하지 않은 열 유형

getNamedParameterJdbcTemplate()대신에 사용하십시오getJdbcTemplate()

 List<Foo> foo = getNamedParameterJdbcTemplate().query("SELECT * FROM foo WHERE a IN (:ids)",parameters,
 getRowMapper());

두 번째 두 인수는 서로 바뀌 었습니다.


2
이것은이 질문에 대한 답변이 아닌 것 같습니다. 다른 답변에 대한 의견이어야합니까?
Dave Schweisguth

2
@DaveSchweisguth 2 년 후, 확실히 답을 보증합니다.
dwjohnston

2

여기를 참조 하십시오

명명 된 매개 변수를 사용하여 쿼리를 작성 ListPreparedStatementSetter하고 모든 매개 변수를 순서대로 사용하십시오. 사용 가능한 매개 변수를 기반으로 기존 형식으로 검색어를 변환하려면 아래 스 니펫을 추가하십시오.

ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(namedSql);

List<Integer> parameters = new ArrayList<Integer>();
for (A a : paramBeans)
    parameters.add(a.getId());

MapSqlParameterSource parameterSource = new MapSqlParameterSource();
parameterSource.addValue("placeholder1", parameters);
// create SQL with ?'s
String sql = NamedParameterUtils.substituteNamedParameters(parsedSql, parameterSource);     
return sql;

나를 위해 이것은 단지 소수의 자리 표시자를 설정하고 싶었던 유일한 답변이었습니다
Kapil

-4

2009 년 이후 많은 것이 바뀌었지만 NamedParametersJDBCTemplate을 사용해야한다는 답변 만 찾을 수 있습니다.

나를 위해 내가 그냥하면 작동합니다

db.query(sql, new MyRowMapper(), StringUtils.join(listeParamsForInClause, ","));

SimpleJDBCTemplate 또는 JDBCTemplate 사용


11
이 솔루션의 문제점은 컨텐츠 listeParamsForInClause가 이스케이프되지 않고 SQL 삽입에 취약하다는 것입니다.
Malax
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.