在JDBC中使用带参数的SQL语句
Posted 荣-
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在JDBC中使用带参数的SQL语句相关的知识,希望对你有一定的参考价值。
ADO.Net中,支持带参数的SQL语句,例如:Select * from Tables where [email protected],其中@column1为SQL参数,使用起来非常方便,而JDBC中没有找到此功能,感觉有点不便, 于是想自己实现一个.今天正好看见csdn中有一篇http://blog.csdn.net/wallimn/article/details/3734242 文章,有些感触,于是把自己的实现也写出来.
我的思路:
1: 在SQL语句中找到以@开始,以" ", "\t", "\n", "\r", ",", ")", ">", "<", "!", "‘", "-", "+", "/"为结束的符号,则会认为是SQL参数.
2: 将SQL语句,按@拆分到一个List中,如果是SQL参数,则在使用的时候,替换为相应的参数值.
分析:
1: 该实现模拟了一个ADO.NET的SQL参数功能(SQLClient下)
2: 坏处是如果SQL语句中原来就包含@的非参数字符串,则会被误认为SQL参数.
实现:
1: 定义SQL语句拆分后的对象,应该包含字符串,以及是否是SQL参数等信息,类如下:
package hij.cache.extension; final class SQLStr { /** * 是否是SQL参数 */ private boolean Param; /** * 对应的文本 */ private String text; /** * 对应的值,一般为Text去除@ */ private String value; public String getValue() { return value; } public boolean isParam() { return Param; } public String getText() { return text; } public void setText(String text) { this.text = text; if(text== null) { return; } if (text.indexOf("@") >= 0) { Param = true; } else { Param = false; } this.text = this.text.replace("\r\n", " ").replace("\r", " ").replace("\t", " ").replace("\n", " "); if (Param) { value = this.text.substring(1); } } }
2: 解析SQL语句,按照@拆分SQL语句,并存储到List<SQLStr>中.
package hij.cache.extension; import java.util.ArrayList; import java.util.List; import hij.util.generic.IFuncP1; /** * 解析带参数的SQL语句 * @author XuminRong * */ final class ParseSQL { /** * 根据@解析字符串,并存储到List中 * @param sql * @return */ public static List<SQLStr> parase(String sql) { List<SQLStr> lst = new ArrayList<SQLStr>(); if (sql == null) { return lst; } int begin = 0; int end = sql.indexOf(‘@‘); while (end >= 0) { String text = sql.substring(begin, end); SQLStr param1 = new SQLStr(); param1.setText(text); lst.add(param1); begin = end; end = getParamEnd(sql, end); if (end != -1) { text = sql.substring(begin, end); SQLStr param2 = new SQLStr(); param2.setText(text); lst.add(param2); } else { break; } begin = end; end = sql.indexOf(‘@‘, begin); } if (begin < sql.length()) { String text = sql.substring(begin, sql.length()); SQLStr param = new SQLStr(); param.setText(text); lst.add(param); } return lst; } /** * SQL语句中,SQL参数的结束符 */ static String[] arr = {" ", "\t", "\n", "\r", ",", ")", ">", "<", "!", "‘", "-", "+", "/"}; /** * 查找下一个SQL参数的位置 * @param sql * @param begin * @return */ private static int getParamEnd(String sql, int begin) { int index = -1; for (int i = 0; i < arr.length; i++) { int pos = sql.indexOf(arr[i], begin); if (index == -1 && pos != -1) { index = pos; continue; } if (pos != -1 && pos < index) { index = pos; } } return index; } /** * 根据回调函数创建对象 * @param lst * @param callback * @return */ public static String createSQL(List<SQLStr> lst, IFuncP1<String, String> callback) { if (lst == null) { return ""; } StringBuilder sb = new StringBuilder(); for (int i = 0; i < lst.size(); i++) { SQLStr info = lst.get(i); if (!info.isParam()) { sb.append(info.getText()); continue; } if (callback == null) { return ""; } String ret = callback.handle(info.getValue()); sb.append(ret == null? "": ret); } return sb.toString(); } }
测试代码:
下面是测试代码:
package hij.cache.extension; import java.util.List; import org.junit.Assert; import org.junit.Test; import hij.util.generic.IFuncP1; public class TestCacheProxy { @Test public void test_Parse_SQL() { String sql = "Select @a @b,@c>,@d<,@e!,@f),‘@g‘,@h\r\n,@i-,@j+,@k/, @l"; List<SQLStr> lst = ParseSQL.parase(sql); String target = ""; for (int i = 0; i < lst.size(); i++) { target += lst.get(i).getText(); } Assert.assertEquals(sql.replace("\r\n", " ").replace("\r", " ").replace("\t", " "), target); sql = "Select @a @b,@c>,@d<,@e!,@f),‘@g‘,@h\r\n,@i-,@j+,@k/"; lst = ParseSQL.parase(sql); target = ""; for (int i = 0; i < lst.size(); i++) { target += lst.get(i).getText(); } Assert.assertEquals(sql.replace("\r\n", " ").replace("\r", " ").replace("\t", " "), target); String sql2 = ParseSQL.createSQL(lst, new IFuncP1<String, String>(){ @Override public String handle(String v) { switch (v) { case "a": { return "a"; } case "b": { return "b"; } case "c": { return "c"; } case "d": { return "d"; } case "e": { return "e"; } case "f": { return "f"; } case "g": { return "g"; } case "h": { return "h"; } case "i": { return "i"; } case "j": { return null; } case "k": { return "k"; } default: { return null; } } } }); Assert.assertEquals(sql2, "Select a b,c>,d<,e!,f),‘g‘,h ,i-,+,k/"); } @Test public void test_Parse_SQL_2() { String sql = "Selecta, b, c, d"; List<SQLStr> lst = ParseSQL.parase(sql); Assert.assertEquals(lst.size(), 1); } }
备注:
1: IFuncP1:
这是一个接口,是我仿照.NET的委托IFunc定义的一个接口,主要是提供一个有返回值且有一个参数的接口,代码如下:
package hij.util.generic; /** * 单参有返回值接口 * @author XuminRong * * @param <P> * @param <T> * */ public interface IFuncP1<P, T> { public T handle(P p); }
备注2:
1: 看了http://blog.csdn.net/wallimn/article/details/3734242#comments后,发现这个博客的思路比我的好,以后可以参考修改,使用PreparedStatement的内在机制,效率和复杂度应该比自己实现要好.
2: 我当前的实现有问题,我希望能实现:
1) 使用SQL参数
2) 同时可以使用String的format功能,这一点似乎不容易做到.
以上是关于在JDBC中使用带参数的SQL语句的主要内容,如果未能解决你的问题,请参考以下文章