在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语句的主要内容,如果未能解决你的问题,请参考以下文章

JDBC SQl 语句 IN 参数的格式是啥

Java调用SQL Server的存储过程详解(转)

PB数据窗口中SQL语句动态LIKE后边加参数如何加?

JDBC statement的常用方法

JDBC存在的问题

带参数的sql语句!不懂