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后,发现这个博客的思路比我的好,以后可以参考修改,使用PreparedStatement的内在机制,效率和复杂度应该比自己实现要好.

2: 我当前的实现有问题,我希望能实现:

1) 使用SQL参数

2) 同时可以使用String的format功能,这一点似乎不容易做到.

看了http://blog.csdn.net/wallimn/article/details/3734242后,对其进行重构及测试,下面是相关代码:

1: 抽象出一个SQL对象:SQLParams,包含SQL语句和参数Map

package hij.cache.extension;

import java.util.HashMap;
import java.util.Map; public final class SQLParams {
String sql;
public String getSql() {
return sql;
}
public void setSql(String sql) {
this.sql = sql;
}
public Map<Integer, String> getParams() {
return params;
}
public void setParams(Map<Integer, String> params) {
this.params = params;
}
Map<Integer, String> params = new HashMap<Integer, String>();
}

  2: 添加SQL参数辅助类:这是对NamedParamSqlUtil的重构.(以一个有单参返回值的接口代替fillParameters的pMap,以@代替:)

package hij.cache.extension;

import java.sql.PreparedStatement;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern; import hij.util.generic.IFuncP1; /**
* SQL参数处理辅助类
* 参考自:http://blog.csdn.net/wallimn/article/details/3734242
* @author XuminRong
*
*/
public final class SQLParamsUtil { /**
* 分析处理带命名参数的SQL语句。使用Map存储参数,然后将参数替换成?
* @param sql
* @return
*/
public static SQLParams parse(String sql) {
SQLParams param = new SQLParams();
String regex = "(@(\\w+))";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(sql);
int idx=1;
while (m.find()) {
//参数名称可能有重复,使用序号来做Key
param.getParams().put(new Integer(idx++), m.group(2));
//System.out.println(m.group(2));
}
String result = sql.replaceAll(regex, "?");
param.setSql(result);
return param;
}
/**
* 使用参数值Map,填充pStat
* @param pStat
* @param pMap 命名参数的值表,其中的值可以比较所需的参数多。
* @return
*/
public static boolean fillParameters(PreparedStatement pStat, SQLParams param, IFuncP1<String,Object> func){
if (pStat == null || param == null) {
return false;
}
if (param.getParams().size() > 0 && func == null) {
return false;
}
for (Integer key : param.getParams().keySet()) {
String paramName = param.getParams().get(key);
Object val = func.handle(paramName);
try
{
pStat.setObject(key, val);
}
catch(Exception ex)
{
ex.printStackTrace();
return false;
}
}
return true;
}
}

  3: 测试程序

	@Test
public void test_SQLParams_parse() {
String sql = "Select @a @b,@c>,@d<,@e!,@f),'@g',@h\r\n,@i-,@j+,@k/, @l";
SQLParams params = SQLParamsUtil.parse(sql); Assert.assertEquals("Select ? ?,?>,?<,?!,?),'?',?\r\n,?-,?+,?/, ?", params.getSql());

Assert.assertEquals(params.getParams().get(3), "c");

	}

  

在JDBC中使用带参数的SQL语句的更多相关文章

  1. 通过带参数的Sql语句来实现模糊查询(多条件查询)

    #region 通过带参数的Sql语句来实现模糊查询(多条件查询) StringBuilder sb = new StringBuilder("select * from books&quo ...

  2. laravel 中的 toSql 获取带参数的 sql 语句

    默认情况下,toSql 获取到的 sql 里面的参数使用 "?" 代替的,如下: DB::table('user')->where('id', 1)->toSql(); ...

  3. .Net ADO拼接带参数的SQL语句

    首先是在DAL数据访问层中的代码://数据更新的方法public static int shuxing_update(s_passnature model) { string sql = " ...

  4. SqlParameter类——带参数的SQL语句

    http://blog.csdn.net/woshixuye/article/details/7218770 SqlParameter 类 表示 SqlCommand 的参数,也可以是它到 DataS ...

  5. ADO.NET中带参数的Sql语句的陷阱

    1.使用Parameter //利用构造函数方式 ,不推荐这样写 Parameter p =new Parameter("@id",值); cmd.Parameters.Add(p ...

  6. 使用带参数的SQL语句向数据库中插入空值

    private void button1_Click(object sender, EventArgs e) { string name = textBox1.Text; int age = Conv ...

  7. ado.net调用带参数的sql语句

  8. JAVA执行带参数的SQL语句

    转自 http://www.cnblogs.com/raymond19840709/archive/2008/05/12/1192948.html

  9. 执行带参数的sql字符串

    --要传入的参数 declare @Rv NVARCHAR(40) --要执行的带参数的sql字符串 declare  @sql nvarchar(max) set @sql='select * fr ...

  10. C#中 如何执行带GO的sql 语句

    C#中是不允许执行带GO的sql 语句的, 如何做呢? 思路就是将带GO的sql语句转化为分段执行, 但在同一事务内执行. 扩展方法是个很不错的主意, 但是尽量不要影响原来的cmd的一些东东, 如 c ...

随机推荐

  1. 9-4 vector对象是如何增长的

    .size():容器中有多少元素 .capacity():不重新分配内存时,可容纳多少元素 .reserve(n):分配至少能容纳n个元素的内存 n>capacity时会分配使得capacity ...

  2. Modbus调试、Modbus Slave、ModScan、Modbus Ploll、串口调试

    记录一下昨天调试Modbus调试. 上位机往下位机发送modbus指令.发送过去之后没有反应.后来才调试出来原来是下位机错一个位. 调试过程:用modScan 往modbus slave 发送modb ...

  3. IPC-7711/21D, IPC-7711D, IPC-7721D 电子组件的返工、修改和维修,验收标准。Rework, Modification and Repair of Electronic Assemblies

    IPC-7711/21 - Revision D - Standard Only: Rework, Modification and Repair of Electronic Assemblies T ...

  4. 多校A层冲刺NOIP2024模拟赛08 排列

    多校A层冲刺NOIP2024模拟赛08 排列 一种连续段 dp 的解法. 题面 小 Y 最近在研究组合数学,他学会了如何枚举排列. 小 Z 最近在研究数论,他学会了求最大公约数. 于是小 Y 和小 Z ...

  5. CommonsCollections3(基于ysoserial)

    环境准备 JDK1.7(7u80).commons-collections(3.x 4.x均可这里使用3.2版本).javassist(3.12.1.GA) JDK:https://repo.huaw ...

  6. 基于Spring源码分析AOP的实现机制

    Spring一个重要的特性就是提供了AOP,使得我们可以在原有的基础上增加我们自己的系统业务逻辑.使得我们系统业务逻辑与应用业务逻辑相分离,耦合性降低,并且大大的提高了开发的效率.Spring的AOP ...

  7. Python:pygame游戏编程之旅一(Hello World)

    按照上周计划,今天开始学习pygame,学习资料为http://www.pygame.org/docs/,学习的程序实例为pygame模块自带程序,会在程序中根据自己的理解加入详细注释,并对关键概念做 ...

  8. 朋友要招几个java,让帮忙出点面试题目

    上周朋友说要招几个高级点的java,网上那些java面试宝典已经被人背得熟透了,让帮忙出出几个面试的问题,主要看看对所使用得语言有较深入得了解,不停留在使用什么开源框架,和对自己一些项目得见解.当然还 ...

  9. 借助AI助手分析LlamaIndex的工作流可视化

    接续上次的讨论,我们上次主要分析了LlamaIndex工作流的核心流程,当前还剩下一行代码需要关注,那就是关于工作流的可视化.今天我们的目标是深入理解这一可视化部分的主要流程,并且对其大体的实现方式进 ...

  10. WxPython跨平台开发框架之参数配置管理界面的设计和实现

    我曾经在2014年在随笔<Winform开发框架之参数配置管理功能实现-基于SettingsProvider.net的构建>介绍过基于.NET开发的参数配置管理界面,本篇随笔基于类似的效果 ...