關于Spring中jdbc的模糊查詢
1、功能需求
對特定的字段進行模糊查詢,并以列表形式返回匹配結果
2、解決思路
使用NamedParameterJdbcTemplate類中的query(String sql, SqlParameterSource paramSource, RowMapper<T> rowMapper)方法,其中sql是查詢語句,paramSource是對應查詢語句中的參數列表,rowMapper是每一行記錄,對應一個對象。
3、發現問題
根據以往的經驗(其實很少),模糊匹配就是where 字段 like '%匹配值%'。然后跟NamedParameterJdbcTemplate的占位符相結合,通過冒號(:)加參數名的方式來代表,即:
...... sql = "... where column like '%:key%'"; paramSource.addValue(key,value); ...... JdbcTemplate.query(sql,paramSource,rowMapper);
匹配的結果是,0(實際上是有滿足條件的)。度娘也沒有太多辦法,只好自己下載spring的源碼去debug了。最關鍵的代碼,就是以下這段:
protected PreparedStatementCreator getPreparedStatementCreator(String sql, SqlParameterSource paramSource) { ParsedSql parsedSql = getParsedSql(sql); String sqlToUse = NamedParameterUtils.substituteNamedParameters(parsedSql, paramSource); Object[] params = NamedParameterUtils.buildValueArray(parsedSql, paramSource, null); List<SqlParameter> declaredParameters = NamedParameterUtils.buildSqlParameterList(parsedSql, paramSource); PreparedStatementCreatorFactory pscf = new PreparedStatementCreatorFactory(sqlToUse, declaredParameters); return pscf.newPreparedStatementCreator(params); }
getParsedSql是用來識別sql中參數的名字和統計參數的個數,識別的標準有:name和:{name}兩種形式;
substituteNamedParameters是將sql中已識別的參數替換為?占位符,如果參數是一個集合類型的話,會把對象里面的屬性遍歷出來,并用?代替,變成最后真正使用的sql語句;
buildValueArray是將輸入參數的值轉化為Object數組;
buildSqlParameterList是將輸入參數的名字轉化為List;
PreparedStatementCreatorFactory新建一個工廠類;
最后利用newPreparedStatementCreator的方法生成并返回PreparedStatementCreator的實現類。
最后找到問題的根源在,getParsedSql-->NamedParameterUtils.parseSqlStatement-->skipCommentsAndQuotes方法中會自動跳過一些字段,下面就是跳過的開始字符和結束字符的匹配規則。
String[] START_SKIP = new String[] {"'", "\"", "--", "/*"}; String[] STOP_SKIP = new String[] {"'", "\"", "\n", "*/"};
首先,spring是通過識別特殊字符來確定參數的數量的,如“:name”。由于我的:key是放在了單引號'的中間,所以就不能夠統計sql中參數的名字和統計參數的個數,因此盡管我的paramSource里面是包含了相應的參數,但程序是不接受的。
4、問題初解決
解決問題的方法,就是sql中不能夠包含單引號',那就這樣吧
...... sql = "... where column like :key"; paramSource.addValue(key,"'%"+value+"%'"); ......
上面的方法,居然還是不行。
5、問題終解決
原來是不需要添加單引號'的
...... sql = "... where column like :key"; paramSource.addValue(key,"%"+value+"%"); ......
后來才發現,jdbc中的參數化查詢,本來就是這樣子的:
sql = "... where column like %?%";
5、經驗總結
其實,很多時候會發現問題的根源是個小問題,但是通過查看源碼找到問題,并解決問題的過程,感覺自己就像個偵探,抽絲剝繭,層層深入,最后謎底解開。哈哈哈~ 就是對自己的鼓勵吧!!!