摘要:最开始我想做的是通过拦截器拦截SQL执行,但是经过测试发现,过滤器至少可以监听每一个SQL的执行与返回结果。因此,将这一次探索过程记录下来。

本文分享自华为云社区《jfinal中使用过滤器监控Druid的SQL执行【五月07】》,作者:KevinQ 。

最开始我想做的是通过拦截器拦截SQL执行,比如类似与PageHelper这种插件,通过拦截器或过滤器,手动修改SQL语句,以实现某些业务需求,比如执行分页,或者限制访问的数据权限等等。但是查到资料说过滤器不是干这个的,干这个的是数据库中间件干的事情,比如MyCat等。

但是经过测试发现,过滤器至少可以监听每一个SQL的执行与返回结果。因此,将这一次探索过程记录下来。

配置过滤器

在jfinal的启动配置类中,有一个函数configPlugin(Plugins me)函数来配置插件,这个函数会在jfinal启动时调用,这个函数的参数是Plugins me,这个参数是一个插件管理器,可以通过这个插件管理器来添加插件。

数据库插件Druid就是在该函数内添加的。

public void configPlugin(Plugins me) {
DruidPlugin druidPlugin = createDruidPlugin_holdoa();
druidPlugin.setPublicKey(p.get("publicKeydebug").trim());
wallFilter = new WallFilter();
wallFilter.setDbType("mysql");
druidPlugin_oa.addFilter(wallFilter);
druidPlugin_oa.addFilter(new StatFilter());
me.add(druidPlugin);
}

我们参考WallFilter以及StatFilter也创建一个过滤器类:

import com.alibaba.druid.filter.FilterEventAdapter;
public class DataScopeFilter extends FilterEventAdapter { }

我们发现FilterEventAdapter中的方法大概有这几个:

public boolean statement_execute(FilterChain chain, StatementProxy statement, String sql) throws SQLException {...}
protected void statementExecuteUpdateBefore(StatementProxy statement, String sql) {...}
protected void statementExecuteUpdateAfter(StatementProxy statement, String sql, int updateCount) {...}
protected void statementExecuteQueryBefore(StatementProxy statement, String sql) {...}
protected void statementExecuteQueryAfter(StatementProxy statement, String sql, ResultSetProxy resultSet) {...}
protected void statementExecuteBefore(StatementProxy statement, String sql) {...}
protected void statementExecuteAfter(StatementProxy statement, String sql, boolean result) {...}

我们复写这几个方法来看一下(排除Update方法,因为我们更关心查询语句)

package xxxx.xxxx;

import com.alibaba.druid.filter.FilterChain;
import com.alibaba.druid.filter.FilterEventAdapter;
import com.alibaba.druid.proxy.jdbc.ResultSetProxy;
import com.alibaba.druid.proxy.jdbc.StatementProxy;
import com.jfinal.kit.LogKit;
import java.sql.SQLException; public class DataScopeFilter extends FilterEventAdapter { @Override
public boolean statement_execute(FilterChain chain, StatementProxy statement, String sql) throws SQLException {
LogKit.info("statement_execute");
return super.statement_execute(chain, statement, sql);
} @Override
protected void statementExecuteQueryBefore(StatementProxy statement, String sql) {
LogKit.info("statementExecuteQueryBefore");
super.statementExecuteQueryBefore(statement, sql);
} @Override
protected void statementExecuteQueryAfter(StatementProxy statement, String sql, ResultSetProxy resultSet) {
LogKit.info("statementExecuteQueryAfter");
super.statementExecuteQueryAfter(statement, sql, resultSet);
} @Override
protected void statementExecuteBefore(StatementProxy statement, String sql) {
LogKit.info("statementExecuteBefore");
super.statementExecuteBefore(statement, sql);
} @Override
protected void statementExecuteAfter(StatementProxy statement, String sql, boolean result) {
LogKit.info("statementExecuteAfter");
super.statementExecuteAfter(statement, sql, result);
} @Override
public ResultSetProxy statement_executeQuery(FilterChain chain, StatementProxy statement, String sql)
throws SQLException {
LogKit.info("statement_executeQuery");
return super.statement_executeQuery(chain, statement, sql);
}
}

然后再config配置类中添加过滤器:

druidPlugin.addFilter(new DataScopeFilter());

发起其执行顺序为:

statement_executeQuery
statementExecuteQueryBefore
statementExecuteQueryAfter

查看父级代码,发现其执行逻辑是,首先执行statement_executeQuery,然后因为调用父级的方法,而父级方法体为:

@Override
public ResultSetProxy statement_executeQuery(FilterChain chain, StatementProxy statement, String sql)
throws SQLException {
statementExecuteQueryBefore(statement, sql); try {
ResultSetProxy resultSet = super.statement_executeQuery(chain, statement, sql); if (resultSet != null) {
statementExecuteQueryAfter(statement, sql, resultSet);
resultSetOpenAfter(resultSet);
} return resultSet;
} catch (SQLException error) {
statement_executeErrorAfter(statement, sql, error);
throw error;
} catch (RuntimeException error) {
statement_executeErrorAfter(statement, sql, error);
throw error;
} catch (Error error) {
statement_executeErrorAfter(statement, sql, error);
throw error;
}
}

从而进一步触发statementExecuteQueryBefore方法与statementExecuteQueryAfter方法。

因此我们,修改statement_executeQuery方法:

 @Override
public ResultSetProxy statement_executeQuery(FilterChain chain, StatementProxy statement, String sql)
throws SQLException { statementExecuteQueryBefore(statement, sql);
ResultSetProxy result = chain.statement_executeQuery(statement, sql);
statementExecuteQueryAfter(statement, sql, result);
return result;
}

如此,便让输出结果为:

statementExecuteQueryBefore
statement_executeQuery
statementExecuteQueryAfter

我们可以在Before或者After方法中添加一些逻辑,比如:记录SQL的实际执行人,操作时间,请求执行SQL的接口。

sql被声明为final类型

发现执行的SQL在Druid中对应的类是:DruidPooledPreparedStatement,其类结构为:

public class DruidPooledPreparedStatement extends DruidPooledStatement implements PreparedStatement {

    private final static Log              LOG = LogFactory.getLog(DruidPooledPreparedStatement.class);

    private final PreparedStatementHolder holder;
private final PreparedStatement stmt;
private final String sql; ....
}

这也就以为着,该类一旦创建,SQL设置后就不允许再修改了,因此,我们需要修改SQL的话,就需要在prepared对象生成之前就修改到对应的执行SQL。

在调试过程中,发现需要覆盖下面这个方法:

@Override
public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection, String sql)
throws SQLException {
// 可以达到修改SQL的目的
sql += " LIMIT 1";
PreparedStatementProxy statement = super.connection_prepareStatement(chain, connection, sql); statementPrepareAfter(statement); return statement;
}

我们可以在这里添加自定义的SQL修改逻辑,比如添加数据权限等等。

点击关注,第一时间了解华为云新鲜技术~

jfinal中如何使用过滤器监控Druid监听SQL执行?的更多相关文章

  1. phalcon: Profiling分析 profilter / Plugin结合,dispatcher调度控制器 监听sql执行日志

    个人觉得profilter 跟 logger 功能差不多,logger的功能在于写入,profilter功能在于sql后及时显示分析.都是对sql执行的的分析:一个是写入log文件,一个是直接在页面展 ...

  2. Blazor和Vue对比学习(基础1.8):Blazor中实现计算属性和数据监听

    1.7章<传递UI片断>,需要做几个案例,这部分暂停消化几天.我们先把基础部分相对简单的最后两章学习了. 计算属性和数据监听是Vue当中的概念,本质上都是监听数据的变化,然后做出响应.两者 ...

  3. 友盟分享到微信 监听不执行 监听只执行onStart,(onResult,onError,onCancel 不执行)

    最近在做一个项目 有一个需求是要分享项目中的一个商品 这对于我来说简直是 so easy (项目是三个人一起写的) 正好看到之前有同事写完了  我就拿过来用吧  一顿复制粘贴  大功告成   这个是监 ...

  4. ThinkPHP 数据库操作(六) : 查询事件、事务操作、监听SQL

    查询事件 查询事件(V5.0.4+) 从 5.0.4+ 版本开始,增加了数据库的CURD操作事件支持,包括: 查询事件仅支持 find . select . insert . update 和 del ...

  5. quartz2.3.0(九)job任务监听器,监听任务执行前、后、取消手动处理方法

    job1任务类 package org.quartz.examples.example9; import java.util.Date; import org.quartz.Job; import o ...

  6. 监听EF执行的sql语句及状态

    1.监听EF执行sql的方式 db.Database.Log += c => Console.WriteLine($"sql:{c}"); SQL Server Profil ...

  7. angularjs中 $watch 和$on 2种监听的区别?

    1.$watch简单使用 $watch是一个scope函数,用于监听模型变化,当你的模型部分发生变化时它会通知你. $watch(watchExpression, listener, objectEq ...

  8. Vue ---- 表单指令 条件指令 循环指令 分隔符 过滤器 计算属性 监听属性

    目录 案例讲解: 一. 表单指令 1.重点: 补充 2.单选框 3.单一复选框 4.多复选框 二 . 条件指令 v-if/v-show ... v-clock 三 . 循环指令 string arra ...

  9. JS 中的事件绑定、事件监听、事件委托

    事件绑定 要想让 JavaScript 对用户的操作作出响应,首先要对 DOM 元素绑定事件处理函数.所谓事件处理函数,就是处理用户操作的函数,不同的操作对应不同的名称. 在JavaScript中,有 ...

随机推荐

  1. Codeforces Round #710 (Div. 3) Editorial 1506A - Strange Table

    题目链接 https://codeforces.com/contest/1506/problem/A 原题 1506A - Strange Table Example input 5 1 1 1 2 ...

  2. 2022.02.20 SA

    2022.02.20 SA 如果我还能看见明天黎明,如果我还能再爬起来,我仍会走我的路,哪怕这条路已经荒废许久,也许我们无法拥有感情,我们甚至无法像个正常人一样接受太阳的洗礼,但是我依然会执行我的条约 ...

  3. 这3个免费PPT素材网站,一定要收藏

    制作PPT,这三个网站的素材绝对够用! 1.象刀设计 https://www.101dao.com 象刀设计里面有非常多PPT模板,这个网站也是主打PPT素材. 分类很清晰,需要什么风格的素材能快速找 ...

  4. Java并发编程扩展(线程通信、线程池)

    之前我说过,实现多线程的方式有4种,但是之前的文章中,我只介绍了两种,那么下面这两种,可以了解了解,不懂没关系. 之前的文章-->Java并发编程之多线程 使用ExecutorService.C ...

  5. 面试突击42:synchronized和ReentrantLock有什么区别?

    在 Java 中,常用的锁有两种:synchronized(内置锁)和 ReentrantLock(可重入锁),二者的功效都是相同得,但又有很多不同点,所以我们今天就来聊聊. 区别1:用法不同 syn ...

  6. zookeeper篇-初识zookeeper

    点赞再看,养成习惯,微信搜索「小大白日志」关注这个搬砖人. 文章不定期同步公众号,还有各种一线大厂面试原题.我的学习系列笔记. 什么是zookeeper? 中间件 作用于分布式系统 支持java.c语 ...

  7. 『现学现忘』Git对象 — 17、Commit对象

    目录 1.Commit对象介绍 2.Commit对象说明 3.本地库中对象之间的关系 4.总结 5.练习 6.本文用到的命令总结 1.Commit对象介绍 现在来介绍最后一种Git对象commit对象 ...

  8. 软件包管理-yum私有仓库

    Linux软件安装 包的依赖关系: 软件包之间可能存在依赖关系,甚至循环依赖,即:A包依赖B包,B包依赖C包,C包依赖A包 安装软件包时,会因为缺少依赖的包,而导致安装包失败. 解决依赖包管理工具: ...

  9. Prometheus监控实战应用

    目录 1.Prometheus的主要特征及概述 2.普罗米修斯原理架构图 3.下载安装启动Prometheus 4.web客户端操作 5.默认图像 6.目录解释 7.配置文件 8.监控指标 8.1.监 ...

  10. 1.17 想学好Linux,这些习惯必须养成(初学者必读)

    不管是在生活还是工作中,每个人都会逐渐养成一些小习惯.坏习惯一旦形成就很难改正,所在在系统学习 Linux之前,给大家一些建议,刻意去培养一些好的习惯,对自己是很有利的. 学习Linux,要习惯使用命 ...