ADO.Net中,支持带参数的SQL语句,例如:Select * from Tables where column1=@column1,其中@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功能,这一点似乎不容易做到.
原文:http://www.cnblogs.com/Rong-/p/5574128.html