西安网站优化服务,wordpress伪静态 nginx,网站建设见站分析和准备论文,重庆妇科医院排名前三前言
很多抓取最终SQL的方法#xff0c;都是带着?的。比如#xff1a; SELECT value from sys_param where name?我们现在想把 #xff1f; 给去掉。有什么办法呢
方法1 编写工具类
#xff08;该方法有些情况下是不适用的#xff0c;比如oracle数据库#xff0c;该…前言
很多抓取最终SQL的方法都是带着?的。比如 SELECT value from sys_param where name?
我们现在想把 给去掉。有什么办法呢
方法1 编写工具类
该方法有些情况下是不适用的比如oracle数据库该工具类就实测不生效oracle或者其它数据库通用的生效方法见方法2.
工具类参考资料来源https://www.cnblogs.com/wggj/p/12762648.html
工具类代码 import oracle.jdbc.internal.OraclePreparedStatement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.sql.PreparedStatement;
import java.sql.SQLException;public class SqlUtil {public static final Logger logger LoggerFactory.getLogger(SqlUtil.class);public static String getSql(PreparedStatement ps) {try {if (ps null || ps.getConnection() null)return null;switch (ps.getConnection().getMetaData().getDatabaseProductName().toUpperCase()) {case ORACLE:OraclePreparedStatement ops (OraclePreparedStatement) ps;ops.getreturn ops.getOriginalSql();case MYSQL:String temp ps.toString();return temp.substring(temp.indexOf(:) 1);case POSTGRESQL:return ps.toString();}} catch (SQLException e) {logger.error(sql异常, e);return null;}return ps.toString();}
}
如何使用该工具类 PreparedStatement ps null;
int count 0;
int ord 1;for (MapString, Object map : data) {// 示例SQLString sql insert into myTest (ORD,INPUT_DATE,LASTUPD_DTM,BILLRECID,YM) values(?,?,?,?,?);ps conn.prepareStatement(sql);ps.setInt(1, ord);java.util.Date utilDate new java.util.Date();java.sql.Date sqlDate new java.sql.Date(utilDate.getTime());ps.setDate(2, sqlDate);ps.setDate(3, sqlDate);ps.setString(4, param.getDefineName());ps.setString(5, zheJiuParamVO.getJizqj());
//使用该工具类打印最终SQLlogger.error(SQL语句 SqlUtil.getSql(ps));ps.executeUpdate();
}方法1在mysql生效oracle实测不生效。直接看方法2
方法2所有数据库(含Oracle)通用方法
思路是这样的我们其实要做的事情就是将所有的?替换为具体的参数。所以我们可以从PreparedStatement入手写一个自定义日志记录的PreparedStatement。
步骤1建立自定义PreparedStatement
建立一个空类自行implements其中方法
public class LoggingPreparedStatement implements PreparedStatement {//自行implements其中方法
}步骤2添加一些自定义方法
读下面代码之前先解释一下是啥意思
首先是添加一个 delegate 代理这个代理只做一件事情就是this.delegate con.prepareStatement(sql);调用原生的 con.prepareStatement(sql) 这样不管是将来走哪个PrepareStatement 的实现类都会进行兼容步骤三还会再次用到这个delegate 然后就是一个打印sql语句的getSQL方法这个方法就是咱们要使用的将来会调用 getSQL 来得到不带 ? 的最终SQL public class LoggingPreparedStatement implements PreparedStatement {private PreparedStatement delegate;private String sql;private MapInteger,Object parameter new TreeMapInteger,Object();public LoggingPreparedStatement(Connection con, String sql) throws SQLException {this.sql sql;//代理this.delegate con.prepareStatement(sql);}//实际打印SQL语句public String getSQL() {String returnSQL sql;//TreeMap returns sorted by keyfor(Object o : parameter.values()) {//Replace first ? with the valuereturnSQL returnSQL.replaceFirst(\\?, o.toString());}return returnSQL;}//下面是自行implements其中方法
//下面是自行implements其中方法
//下面是自行implements其中方法
//下面是自行implements其中方法
// .....
// .....
// .....
}步骤3利用delegate (代理) 重写原有的PreparedStatement方法
示例
主要做了这样的事情parameter这个全局变量是我们getSQL()打印要用到的利用delegate执行原生的PreparedStatement方法的同时将变量参数塞入 parameter 中。
注意业务代码中有多少 setXXX这里就要重写多少个
Overridepublic void setString(int parameterIndex, String x) throws SQLException {parameter.put(parameterIndex, x);delegate.setString(parameterIndex, x);}
Overridepublic void setDate(int parameterIndex, Date x) throws SQLException {parameter.put(parameterIndex, x);delegate.setDate(parameterIndex, x);}
Overridepublic void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException {parameter.put(parameterIndex, x);delegate.setObject(parameterIndex, x);}步骤4 修改业务代码让其适配自定义PreparedStatement并且打印日志
PreparedStatement ps null;
int count 0;
int ord 1;
try {conn.setAutoCommit(false);for (MapString, Object map : data) {// 示例SQLString sql insert into myTest (ORD,INPUT_DATE,LASTUPD_DTM,BILLRECID,YM) values(?,?,?,?,?);// 重点替换PreparedStatement// 重点替换PreparedStatementps new LoggingPreparedStatement(conn, sql);
// ps conn.prepareStatement(sql);ps.setInt(1, ord);java.util.Date utilDate new java.util.Date();java.sql.Date sqlDate new java.sql.Date(utilDate.getTime());ps.setDate(2, sqlDate);ps.setDate(3, sqlDate);ps.setString(4, param.getDefineName());ps.setString(5, zheJiuParamVO.getJizqj());//使用和打印logger.error(最终SQL ((LoggingPreparedStatement) ps).getSQL());ps.executeUpdate();}最终效果
我们看到即使是Oracle也能在log中打印不带的最终SQL
11:06:03.180 [http-nio-8090-exec-1] ERROR SQL
insert into myTest(ORD,INPUT_DATE,LASTUPD_DTM,BILLRECID,YM,order_no,zc_code,jqid,zj_month,zc_name,input_user,zj_amt,sz_name,zc_type) values(85834,2023-08-25,2023-08-25,bill.AssetDepreciationBillDefine,202307,202307,TY2023000504,89a79051-c000-0021-597d-4e70c0c5cae0,1,桌面工作站,系统,156.81,教学,2010199)
大功告成