在JDBC中使用带参数的SQL语句
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语句的更多相关文章
- 通过带参数的Sql语句来实现模糊查询(多条件查询)
#region 通过带参数的Sql语句来实现模糊查询(多条件查询) StringBuilder sb = new StringBuilder("select * from books&quo ...
- laravel 中的 toSql 获取带参数的 sql 语句
默认情况下,toSql 获取到的 sql 里面的参数使用 "?" 代替的,如下: DB::table('user')->where('id', 1)->toSql(); ...
- .Net ADO拼接带参数的SQL语句
首先是在DAL数据访问层中的代码://数据更新的方法public static int shuxing_update(s_passnature model) { string sql = " ...
- SqlParameter类——带参数的SQL语句
http://blog.csdn.net/woshixuye/article/details/7218770 SqlParameter 类 表示 SqlCommand 的参数,也可以是它到 DataS ...
- ADO.NET中带参数的Sql语句的陷阱
1.使用Parameter //利用构造函数方式 ,不推荐这样写 Parameter p =new Parameter("@id",值); cmd.Parameters.Add(p ...
- 使用带参数的SQL语句向数据库中插入空值
private void button1_Click(object sender, EventArgs e) { string name = textBox1.Text; int age = Conv ...
- ado.net调用带参数的sql语句
- JAVA执行带参数的SQL语句
转自 http://www.cnblogs.com/raymond19840709/archive/2008/05/12/1192948.html
- 执行带参数的sql字符串
--要传入的参数 declare @Rv NVARCHAR(40) --要执行的带参数的sql字符串 declare @sql nvarchar(max) set @sql='select * fr ...
- C#中 如何执行带GO的sql 语句
C#中是不允许执行带GO的sql 语句的, 如何做呢? 思路就是将带GO的sql语句转化为分段执行, 但在同一事务内执行. 扩展方法是个很不错的主意, 但是尽量不要影响原来的cmd的一些东东, 如 c ...
随机推荐
- 9-4 vector对象是如何增长的
.size():容器中有多少元素 .capacity():不重新分配内存时,可容纳多少元素 .reserve(n):分配至少能容纳n个元素的内存 n>capacity时会分配使得capacity ...
- Modbus调试、Modbus Slave、ModScan、Modbus Ploll、串口调试
记录一下昨天调试Modbus调试. 上位机往下位机发送modbus指令.发送过去之后没有反应.后来才调试出来原来是下位机错一个位. 调试过程:用modScan 往modbus slave 发送modb ...
- 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 ...
- 多校A层冲刺NOIP2024模拟赛08 排列
多校A层冲刺NOIP2024模拟赛08 排列 一种连续段 dp 的解法. 题面 小 Y 最近在研究组合数学,他学会了如何枚举排列. 小 Z 最近在研究数论,他学会了求最大公约数. 于是小 Y 和小 Z ...
- CommonsCollections3(基于ysoserial)
环境准备 JDK1.7(7u80).commons-collections(3.x 4.x均可这里使用3.2版本).javassist(3.12.1.GA) JDK:https://repo.huaw ...
- 基于Spring源码分析AOP的实现机制
Spring一个重要的特性就是提供了AOP,使得我们可以在原有的基础上增加我们自己的系统业务逻辑.使得我们系统业务逻辑与应用业务逻辑相分离,耦合性降低,并且大大的提高了开发的效率.Spring的AOP ...
- Python:pygame游戏编程之旅一(Hello World)
按照上周计划,今天开始学习pygame,学习资料为http://www.pygame.org/docs/,学习的程序实例为pygame模块自带程序,会在程序中根据自己的理解加入详细注释,并对关键概念做 ...
- 朋友要招几个java,让帮忙出点面试题目
上周朋友说要招几个高级点的java,网上那些java面试宝典已经被人背得熟透了,让帮忙出出几个面试的问题,主要看看对所使用得语言有较深入得了解,不停留在使用什么开源框架,和对自己一些项目得见解.当然还 ...
- 借助AI助手分析LlamaIndex的工作流可视化
接续上次的讨论,我们上次主要分析了LlamaIndex工作流的核心流程,当前还剩下一行代码需要关注,那就是关于工作流的可视化.今天我们的目标是深入理解这一可视化部分的主要流程,并且对其大体的实现方式进 ...
- WxPython跨平台开发框架之参数配置管理界面的设计和实现
我曾经在2014年在随笔<Winform开发框架之参数配置管理功能实现-基于SettingsProvider.net的构建>介绍过基于.NET开发的参数配置管理界面,本篇随笔基于类似的效果 ...