前言

本文主要给大家介绍了关于利用JDBC的PrepareStatement打印真实SQL的相关内容,分享出来供大家参考学习,下面来一起看看详细的介绍:
我们知道,JDBC 的 PrepareStatement 优点多多,通常都是推荐使用 PrepareStatement 而不是其基类 Statment。PrepareStatement 支持 ? 占位符,可以将参数按照类型转自动换为真实的值。既然这一过程是自动的,封装在 JDBC 内部的,那么我们外部就不得而知目标的 SQL 最终生成怎么样——于是在调试过程中便有一个打印 SQL 的问题。我们对 PrepareStatement 传入 SQL 语句,如 SELECT * FROM table WHERE id = ?,然后我们传入对应的 id 参数,假设是 id = 10,那怎么把得到参数的 SELECT * FROM table WHERE id = 12 结果完整地得出来呢?——这便是本文所要探讨的问题。下面话不多说了,来一起看看详细的介绍:
方法如下:
首先,我们看看典型的一个 PrepareStatement 调用方法,如下一个函数,
/**
* 查询单个结果,保存为 Map<String, Object> 结构。如果查询不到任何数据返回 null。
*
* @param conn
* 数据库连接对象
* @param sql
* SQL 语句,可以带有 ? 的占位符
* @param params
* 插入到 SQL 中的参数,可单个可多个可不填
* @return Map<String, Object> 结构的结果。如果查询不到任何数据返回 null。
*/
public static Map<String, Object> query(Connection conn, String sql, Object... params) {
Map<String, Object> map = null;
printRealSql(sql, params); // 打印真实 SQL 的函数
try (PreparedStatement ps = conn.prepareStatement(sql);) {
if(params != null)
for (int i = 0; i < params.length; i++)
ps.setObject(i + 1, params[i]);
try (ResultSet rs = ps.executeQuery();) {
if (rs.isBeforeFirst()) {
map = getResultMap(rs);
} else {
LOGGER.info("查询 SQL:{0} 没有符合的记录!", sql);
}
}
} catch (SQLException e) {
LOGGER.warning(e);
}
return map;
}
值得注意该函数里面:
printRealSql(sql, params); // 打印真实 SQL 的函数
其参数一 sql 就是类似 SELECT * FROM table WHERE id = ? 的语句,参数二 params 为 Object... params 的参数列表,可以是任意类似的合法 SQL 值。最后,通过 printRealSql 函数最终得出形如 SELECT * FROM table WHERE id = 12 的结果。
printRealSql 函数源码如下:
/**
* 在开发过程,SQL语句有可能写错,如果能把运行时出错的 SQL 语句直接打印出来,那对排错非常方便,因为其可以直接拷贝到数据库客户端进行调试。
*
* @param sql
* SQL 语句,可以带有 ? 的占位符
* @param params
* 插入到 SQL 中的参数,可单个可多个可不填
* @return 实际 sql 语句
*/
public static String printRealSql(String sql, Object[] params) {
if(params == null || params.length == 0) {
LOGGER.info("The SQL is------------>\n" + sql);
return sql;
}
if (!match(sql, params)) {
LOGGER.info("SQL 语句中的占位符与参数个数不匹配。SQL:" + sql);
return null;
}
int cols = params.length;
Object[] values = new Object[cols];
System.arraycopy(params, 0, values, 0, cols);
for (int i = 0; i < cols; i++) {
Object value = values[i];
if (value instanceof Date) {
values[i] = "'" + value + "'";
} else if (value instanceof String) {
values[i] = "'" + value + "'";
} else if (value instanceof Boolean) {
values[i] = (Boolean) value ? 1 : 0;
}
}
String statement = String.format(sql.replaceAll("\\?", "%s"), values);
LOGGER.info("The SQL is------------>\n" + statement);
ConnectionMgr.addSql(statement); // 用来保存日志
return statement;
}
/**
* ? 和参数的实际个数是否匹配
*
* @param sql
* SQL 语句,可以带有 ? 的占位符
* @param params
* 插入到 SQL 中的参数,可单个可多个可不填
* @return true 表示为 ? 和参数的实际个数匹配
*/
private static boolean match(String sql, Object[] params) {
if(params == null || params.length == 0) return true; // 没有参数,完整输出
Matcher m = Pattern.compile("(\\?)").matcher(sql);
int count = 0;
while (m.find()) {
count++;
}
return count == params.length;
}
可见,上述思路是非常简单的,——有多少个 ? 占位符,就要求有多少个参数,然后一一对照填入(数组)。match 函数会检查第一个步骤,检查个数是否匹配,否则会返回“SQL 语句中的占位符与参数个数不匹配”的提示;然后,参数的值会被转换为符合 SQL 值所要求的类型;最后,就是将 SQL 一一填入,——此处使用了一个字符串的技巧,先把 ? 字符通通转换为 %s,——那是 String.format 可识别的占位符,如此再传入 Object[] 参数列表,即可得出我们期待的 SQL 结果。
我们不能保证那 SQL 可以直接放到数据库中被解析。因为我们的初衷只是把 SQL 打印出来,务求更近一步让程序员在开发阶段看到 SQL 是怎么样子的,而且不是一堆 ?、?……,这样会显得更符合真实情形一点。
PrepareStatement 内部源码肯定有这一步骤或者某个变量是表示那个真实 SQL 的,——只是没有暴露出来。如果有,那么对程序员会更友好一些。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对的支持。
# preparestatement
# sql
# preparestatement用法
# preparestatement方法
# Java JDBC基本使用方法详解
# Java jdbc批量多线程读取CVS文件入库
# Java使用JDBC连接postgresql数据库示例
# Java实现JDBC连接数据库简单案例
# java使用jdbc连接数据库简单实例
# Java连接数据库JDBC技术之prepareStatement的详细介绍
# 多个
# 这一
# 可以直接
# 可不填
# 转换为
# 填入
# 有多少个
# 打印出来
# 不匹配
# 是在
# 相关内容
# 第一个
# 那是
# 有可能
# 说了
# 是怎么
# 不多
# 推荐使用
# 给大家
# 为其
相关文章:
如何在IIS中配置站点IP、端口及主机头?
如何通过商城免费建站系统源码自定义网站主题?
Swift中swift中的switch 语句
浅析上传头像示例及其注意事项
已有域名如何快速搭建专属网站?
如何在Ubuntu系统下快速搭建WordPress个人网站?
MySQL查询结果复制到新表的方法(更新、插入)
西安专业网站制作公司有哪些,陕西省建行官方网站?
网站制作与设计教程,如何制作一个企业网站,建设网站的基本步骤有哪些?
陕西网站制作公司有哪些,陕西凌云电器有限公司官网?
企业在线网站设计制作流程,想建设一个属于自己的企业网站,该如何去做?
无锡营销型网站制作公司,无锡网选车牌流程?
官网自助建站平台指南:在线制作、快速建站与模板选择全解析
深圳网站制作平台,深圳市做网站好的公司有哪些?
国美网站制作流程,国美电器蒸汽鍋怎么用官方网站?
建站之星代理平台如何选择最佳方案?
如何快速重置建站主机并恢复默认配置?
如何在Windows虚拟主机上快速搭建网站?
建站主机无法访问?如何排查域名与服务器问题
,网站推广常用方法?
,购物网站怎么盈利呢?
如何在Golang中使用replace替换模块_指定本地或远程路径
如何用虚拟主机快速搭建网站?详细步骤解析
高端企业智能建站程序:SEO优化与响应式模板定制开发
制作旅游网站html,怎样注册旅游网站?
如何通过多用户协作模板快速搭建高效企业网站?
网站图片在线制作软件,怎么在图片上做链接?
怀化网站制作公司,怀化新生儿上户网上办理流程?
制作公司内部网站有哪些,内网如何建网站?
如何生成腾讯云建站专用兑换码?
,网页ppt怎么弄成自己的ppt?
成都响应式网站开发,dw怎么把手机适应页面变成网页?
长春网站建设制作公司,长春的网络公司怎么样主要是能做网站的?
成都网站制作价格表,现在成都广电的单独网络宽带有多少的,资费是什么情况呢?
如何选择靠谱的建站公司加盟品牌?
微信小程序 五星评分(包括半颗星评分)实例代码
如何在VPS电脑上快速搭建网站?
建站之星安装后如何配置SEO及设计样式?
相亲简历制作网站推荐大全,新相亲大会主持人小萍萍资料?
在线ppt制作网站有哪些,请推荐几个好的课件下载的网站?
建站之星如何实现网站加密操作?
电商网站制作公司有哪些,1688网是什么意思?
红河网站制作公司,红河事业单位身份证如何上传?
建站之星北京办公室:智能建站系统与小程序生成方案解析
如何在橙子建站上传落地页?操作指南详解
C#如何使用XPathNavigator高效查询XML
制作销售网站教学视频,销售网站有哪些?
建站之星安全性能如何?防护体系能否抵御黑客入侵?
山东云建站价格为何差异显著?
北京制作网站的公司,北京铁路集团官方网站?
*请认真填写需求信息,我们会在24小时内与您取得联系。