今天在使用PreparedStatement進行預編譯時,發現使用IN(String) 傳入一個字符串一逗號為分隔符卻失效,例如傳入"a,b,c", 查詢的不是"a" "b" "c"三個數據,而是"a,b,c"一個數據
SELECT d.* FROM TLK_列表_分頁 d WHERE 1=1 AND ITEM_多行文本二 IN ( ?)
這條語句中的參數在使用PrepareStatement來預編譯之后,是不可以傳入一個拼接字符串的,比如
String test="'a','b','c'";
prepareStatement.setString(1,test);
想要達到執行效果
SELECT d.* FROM TLK_列表_分頁 d WHERE 1=1 AND ITEM_多行文本二 IN ('a','b','c')
但是實際執行的sql語句是:
SELECT d.* FROM TLK_列表_分頁 d WHERE 1=1 AND ITEM_多行文本二 IN ('a'',''b'',''c')
它不是查詢 'a','b','c'這三個元素,而是查詢'a,b,c,'這一個元素,所以達不到預期的效果
后來想過既然它插入的字符串是逗號兩邊少了單引號的話我就replace把 ","換成" ',' "
這樣以后實際執行的sql語句是:
SELECT d.* FROM TLK_列表_分頁 d WHERE 1=1 AND ITEM_多行文本二 IN ('a'',''b'',''c')
單引號變成了雙引號,其實是sql防注入起了作用,它對單引號自動進行了轉義 ' 變成了 '' 給單引號加多一個引號進行了轉義。
於是只好使用笨辦法,
String test里面有幾個參數,那就有幾個占位符 ?
就是當 String test="'a','b','c'"; 有兩個逗號時,sql就應該是:
SELECT d.* FROM TLK_列表_分頁 d WHERE 1=1 AND ITEM_多行文本二 IN ( ?,?,?)
這樣就OK了。
添加占位符的代碼如下:
String temp = "IN ( ? ";
//判斷逗號出現的次數 int n = test.length() - test.replaceAll(",", "").length(); //根據參數的數量決定占位符的數量 if (sql.contains(temp)) {
//循環添加占位符的次數要比逗號出現的次數多一次,即參數的數量。 for (int i = 0; i < n; i++) { sql = sql.replace(temp, temp + ",?"); temp = temp + ",?"; } } }
這樣為sql添加了對應的占位符后,如果不把test字符串進行切割,依然會報錯,因為如果進行了添加占位符,你的sql變成了
SELECT d.* FROM TLK_列表_分頁 d WHERE 1=1 AND ITEM_多行文本二 IN ( ?,?,?)
這樣你就需要傳入三個參數,僅僅是傳入“a,b,c”的話是滿足不了條件的。
List<Object> sqlParameters; if (text.contains(",")) { int n = text.length() - text.replaceAll(",", "").length(); //切割參數添加到sqlParameters for (int i = 0; i <= n; i++) { String s = text.split(",")[i]; sqlParameters.add(i, text.split(",")[i]); } //添加完切割的參數后刪除原來未切割的參數 sqlParameters.remove(text); }
用List切割完以后就可以傳入數據了。
for (Object sqlParameter : sqlParameters) { parameterIndex++; if (sqlParameter instanceof String) { preparedStatement.setString(parameterIndex, (String) sqlParameter); }
這個寫法是可以滿足PG數據庫的
可以參考網站:https://blog.csdn.net/lismooth/article/details/76934980