在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 ...
随机推荐
- C++学习——访问修饰符
一.类是什么 类是C++当中的一个集合,定义了"属性",通过类可以实例化对象,此时对象的属性就囊括在这个类当中.比如: class student { public: string ...
- 卡特兰数 Catalan 数列
卡特兰数 Catalan 数列 引入 有一个无限大的栈,进栈的顺序为 \(1,2,\cdots,n\),求有多少种不同的出栈序列. 设 \(h[n]\) 为 \(n\) 个数的出栈序列方案数. 可以这 ...
- python模块导入规则(相对导入和绝对导入)
python模块可以相对导入和绝对导入,但这两者是不能随意替换使用的.本文主要讨论工作目录下模块之间的导入规则.其中相对导入前面有一个'.',表示从该脚本所在目录开始索引,而绝对导入前面没有'.',表 ...
- 桌面应用开发之Electron
Electron 官网: https://www.electronjs.org/ Electron是一个使用JavaScript.HTML和CSS构建跨平台的桌面应用程序.它基于Node.js和Chr ...
- Python之pandas操作
中文网:https://www.pypandas.cn/ Pandas 是 Python 的核心数据分析支持库,提供了快速.灵活.明确的数据结构,旨在简单.直观地处理关系型.标记型数据.Pandas ...
- C#/.NET/.NET Core优秀项目和框架2024年11月简报
前言 公众号每月定期推广和分享的C#/.NET/.NET Core优秀项目和框架(每周至少会推荐两个优秀的项目和框架当然节假日除外),公众号推文中有项目和框架的详细介绍.功能特点.使用方式以及部分功能 ...
- uniapp h5 和 小程序互相传值
小程序端 <template> <div> <web-view :webview-styles="webviewStyles" :src=" ...
- GPUStack v0.4:文生图模型、语音模型、推理引擎版本管理、离线支持和部署本地模型
GPUStack 是一个专为运行 AI 模型设计的开源 GPU 集群管理器,致力于支持基于任何品牌的异构 GPU 构建统一管理的算力集群.无论这些 GPU 运行在 Apple Mac.Windows ...
- manim边做边学--图形的创建与销毁
上一篇介绍了文字相关的创建和销毁动画,本篇介绍几个用于几何图形的创建和销毁动画效果类. Create:用于在场景中生成一个完整的Mobject(可渲染对象) Uncreate:是Create的逆操作, ...
- Xcode Swift自动格式化
Xcode Swift自动格式化 安装SwiftFormat SwiftFormat 是一款用来格式化Swift代码的命令行工具. 直接用Homebrew安装 brew install swiftfo ...