控制台打印完整sql(包含参数)

之前看到的分享基本围绕“日志”功能展开,尽管有些已经挺简单了,但还是觉得可以在操作步骤上简化。现介绍如下:

一、基本需求:开发阶段,需要检查最终执行的sql语句——不仅仅是带有“?”的预编译语句,还应该包括各个字段的参数。

拒绝形如:select * from worker where id = ?  or name = ?

改造目标:select * from worker where id = 2 or name = WangWei

二、基本思路:为数据源插件DruidPlugin添加过滤Filter。

三、步骤:

1、新建类MyDruidFilter

public class MyDruidFilter extends FilterAdapter {
    @Override
    public void statement_close(FilterChain chain, StatementProxy statement) throws SQLException {
        super.statement_close(chain, statement);
        Map<Integer, JdbcParameter> lParameters = statement.getParameters();
        String lSql = statement.getBatchSql();
        if(StrKit.notBlank(lSql)){
            for (Map.Entry<Integer,JdbcParameter> lEntry : lParameters.entrySet()){
                JdbcParameter lValue = lEntry.getValue();
                if(lValue == null){
                    continue;
                }
                Object lO = lValue.getValue();
                if(lO == null){
                    continue;
                }
                String lS = lO.toString();
                lSql = lSql.replaceFirst("\\?",lS);
            }
            System.out.println("Sql = " + lSql);
        }
    }
}

注意:1)这个类继承了FilterAdapter。2)这里重载方法有很多选择,并非一定要选statement_close

2、项目的Config的ConfigPlugin(Plugins me)中进行适当改写

@Override
public void configPlugin(Plugins me) {
    // 配置数据库插件
    DruidPlugin druidPlugin = getDruidPlugin();
    if (prop.getBoolean("devMode", false)){
        //打印完整sql语句,核心语句就这一句
        druidPlugin.addFilter(new MyDruidFilter());
    }
    。。。
}


仅两步!即可达成目标!

评论区

快乐的蹦豆子

2019-11-19 14:42

Log4jFilter logFilter = new Log4jFilter();
logFilter.setStatementLogEnabled(false);
logFilter.setStatementLogErrorEnabled(true);
logFilter.setStatementExecutableSqlLogEnable(true);
dbPlugin.addFilter(logFilter);
其实这样就可以了

麻言

2019-11-19 14:52

@快乐的蹦豆子 你的方法报错:Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/log4j/Priority

麻言

2019-11-19 15:04

@快乐的蹦豆子 显然是缺少依赖。缺什么依赖呢?这个问题也不简单吧。

happyboy

2019-11-19 15:04

还有一个办法,就是借助p6spy插件,这个插件对所有框架都适用。

山东小木

2019-11-19 15:30

使用Druid的Filter就行了

JFinal

2019-11-19 16:00

这个方案比以前那个方案还简洁:
https://www.jfinal.com/share/492

谢谢分享,赞

jounzhang

2019-11-23 11:24

druid新版本自带了这个功能的,参见com.alibaba.druid.filter.logging.LogFilter,它有很多实现类,提供了对log4j、log4j2、slf4j等的支持,还提供了丰富的配置,全是set方法,设置true/false就行

Psbye

2019-11-26 18:13

简单的修改了一下打印的语句,不然日志里面的语句是不能直接用的哦~


package plus.jfinal.plugin.datasource.mysql.filter;


import com.alibaba.druid.filter.FilterAdapter;
import com.alibaba.druid.filter.FilterChain;
import com.alibaba.druid.proxy.jdbc.JdbcParameter;
import com.alibaba.druid.proxy.jdbc.StatementProxy;
import com.jfinal.kit.StrKit;

import java.sql.SQLException;
import java.util.Map;

public class SqlPrintDruidFilter extends FilterAdapter {

@Override
public void statement_close(FilterChain chain, StatementProxy statement) throws SQLException {
super.statement_close(chain, statement);
Map lParameters = statement.getParameters();
String lSql = statement.getBatchSql();
if(StrKit.notBlank(lSql)){
for (Map.Entry lEntry : lParameters.entrySet()){
JdbcParameter lValue = lEntry.getValue();
if(lValue == null){
continue;
}
Object lO = lValue.getValue();
if(lO == null){
continue;
}
String lS = lO.toString();
//java.sql.Types
switch(lValue.getSqlType()){
case 12 :
lS = "'"+lS+"'";
//语句
break; //可选
case 1 :
lS = "'"+lS+"'";
//语句
break; //可选
case 91 :
lS = "'"+lS+"'";
//语句
break; //可选
}
lSql = lSql.replaceFirst("\\?",lS);
}
System.out.println("Sql: " + lSql);
}
}
}

zzutligang

2019-11-28 10:26

@Psbye,经过这么一改,就完美了,否则之前的update语句后面的参数不带引号。

琴海森林

2020-05-07 10:30

@Psbye 添加一个时间参数转换,这样就完美了
if(lO instanceof Date){
lO =DateKit.toStr((Date)lO ,"yyyy-MM-dd HH:mm:ss");
}

chcode

2021-05-10 11:20

这里有更加极简的方案https://jfinal.com/share/2250

fmpoffice

2022-05-01 19:56

配置之后,不生效,能否ActiveRecordPlugin的setShowSql直接实现啊?

// 配置 ActiveRecordPlugin
ActiveRecordPlugin arp = new ActiveRecordPlugin(druidPlugin);
arp.setShowSql(p.getBoolean("devMode", false)); // 是否输出 sql 到控制台

fmpoffice

2022-05-01 20:02

@fmpoffice 可以了,谢谢

热门分享

扫码入社