SpringJDBC的in查詢用法

JdbcTemplate的query方法

JdbcTemplate的query中sql是用?佔位符的方式進行傳參的。
方法定義如下:

<T> List<T> query(String sql, Object[] args, int[] argTypes, RowMapper<T> rowMapper)

這個方法本身不支持in查詢,我們在調用前,可以自己封裝一層方法,變相的實現in查詢。

public <T> List<T> querySupportIn(String sql, Object[] args, RowMapper<T> rowMapper) throws DataAccessException {
	Object[] obj = this.changeMessage(sql, args);
	return this.getJdbcTemplate().query((String)obj[0], (Object[])obj[1], (int[])obj[2], rowMapper);
}
private Object[] changeMessage(String sql, Object[] args) throws DataAccessException {
	List<Object> params = new ArrayList<Object>();
	List<Integer> types = new ArrayList<Integer>();
	List<Object[]> paramList = new ArrayList<Object[]>();
	for(int i=0;i<args.length;i++){
		Object arg = args[i];
		if(arg.getClass().isArray()){
			Object[] array = (Object[]) arg;
			if(array.length == 0){
				throw new RuntimeException("Array param can not be empty!");
			}
			Integer type = null;
			for(Object obj : array){
				if(type == null){
					type = this.getTypes(obj);
				}
				params.add(obj);
				types.add(type);
			}
			if(array.length > 1){
				paramList.add(new Object[]{i, getParamSymbol(array.length)});
			}
		}else if(Collection.class.isAssignableFrom(arg.getClass()) ){
			Collection<?> list = (Collection<?>) arg;
			if(list.size() == 0){
				throw new RuntimeException("Collection param can not be empty!");
			}
			Integer type = null;
			for(Object obj : list){
				if(type == null){
					type = this.getTypes(obj);
				}
				params.add(obj);
				types.add(type);
			}
			if(list.size() > 1){
				paramList.add(new Object[]{i, getParamSymbol(list.size())});
			}
		}else{
			params.add(arg);
			types.add(this.getTypes(arg));
		}
	}
	//根據序號替換單個?爲多個數組?
	if(!paramList.isEmpty()){
		StringBuffer sqlb = new StringBuffer();
		String sqls = sql.toString();
		int count = -1;
		int index = -1;
		for(Object[] obj : paramList){
			int paramIndex = (Integer)obj[0];
			while(true){
				count++;
				index = sqls.indexOf("?", index + 1);
				if(index == -1 ){
					throw new RuntimeException("Paramater size > '?' size!");
				}
				if(paramIndex == count){
					sqlb.append(sqls.substring(0,index))
						.append((String)obj[1]);
					sqls = sqls.substring(index+1);
					index = -1;
					break;
				}
			}
		}
		sqlb.append(sqls);
		sql = sqlb.toString();
	}

	int[] tys = new int[types.size()];
	for(int i=0;i<types.size();i++){
		tys[i] = types.get(i);
	}
	if(logger.isInfoEnabled()){
		logger.info("sql  : "+sql.toString());
		logger.info("param: "+params);
		logger.info("types: "+types);
	}
	return new Object[]{sql , params.toArray(), tys};
}

changeMessage方法的主要作用就是獲取Object[] args參數中所有的個數(包括數組套數組的個數),根據args的個數,把傳入的String sql參數中的所有?佔位符重新替換一遍。

使用如下方式調用

String sql = "SELECT * FROM t1 WHERE type = ? AND id IN (?)";
String[] ids = new String[]{"a", "b"};
Object[] params = new Object[]{sql, ids};
List<Test> result = this.querySupportIn(sql, params, new BeanPropertyRowMapper<>(Test.class));

在querySupportIn內部調用的changeMessage方法中,處理後的sql就變成SELECT * FROM t1 WHERE type = ? AND id IN (?,?)了,這樣就變相實現了in查詢。

NamedParameterJdbcTemplate的queryForList方法

NamedParameterJdbcTemplate的queryForList方法中sql是用具名參數SQL按名稱(以冒號開頭)的方式進行傳參的。
方法定義如下:

<T> List<T> queryForList(String sql, SqlParameterSource paramSource, Class<T> elementType) throws DataAccessException

使用如下方式調用

String sql = "SELECT * FROM t1 WHERE type = :type AND id IN (:ids)";
Map<String, Object> paramsMap = new HashMap<>();
paramsMap.put("type", 1);
String[] ids = new String[]{"a", "b"};
paramsMap.put("ids", ids);
List<Test> result = namedParameterJdbcTemplate.query(sql, paramsMap, new BeanPropertyRowMapper<>(Test.class));

NamedParameterJdbcTemplate的query方法,本身就支持in查詢,此處不再做封裝處理。

總結

NamedParameterJdbcTemplate的使用好處:如果參數比較多,並且參數位置或順序可能變化的情況下,使用NamedParameterJdbcTemplate是非常方便的!

參考資料
詳解jdbcTemplate和namedParameterJdbcTemplate

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章