当前位置:网站首页>jfinal中如何使用过滤器监控Druid监听SQL执行?
jfinal中如何使用过滤器监控Druid监听SQL执行?
2022-06-30 20:09:00 【游戏编程】
摘要: 最开始我想做的是通过拦截器拦截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_executeQuerystatementExecuteQueryBeforestatementExecuteQueryAfter查看父级代码,发现其执行逻辑是,首先执行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; }如此,便让输出结果为:
statementExecuteQueryBeforestatement_executeQuerystatementExecuteQueryAfter我们可以在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修改逻辑,比如添加数据权限等等。
点击关注,第一时间了解华为云新鲜技术~
作者:华为云开发者联盟
游戏编程,一个游戏开发收藏夹~
如果图片长时间未显示,请使用Chrome内核浏览器。
边栏推荐
- 基于开源流批一体数据同步引擎ChunJun数据还原—DDL解析模块的实战分享
- Description of the latest RTSP address rules for Hikvision camera, NVR, streaming media server, playback and streaming [easy to understand]
- 杰理之关于长按开机检测抬起问题【篇】
- 北京大学ACM Problems 1005:I Think I Need a Houseboat
- 杰理之用测试盒配对软件修改注意点【篇】
- Static classes use @resource annotation injection
- 数据库 OLAP、OLTP是什么?相同和不同?适用场景
- STL的基本组成部分
- 哈夫曼樹(一)基本概念與C語言實現
- CADD course learning (1) -- basic knowledge of drug design
猜你喜欢

Huffman tree (I) basic concept and C language implementation

项目经理是领导吗?可以批评指责成员吗?
![Jerry's touch key recognition process [chapter]](/img/3e/bb73c735d0a7c7a26989c65a432dad.png)
Jerry's touch key recognition process [chapter]

1、生成对抗网络入门

25:第三章:开发通行证服务:8:【注册/登录】接口:接收并校验“手机号和验证码”参数;(重点需要知道【利用redis来暂存数据,获取数据的】的应用场景)(使用到了【@Valid注解】参数校验)

exness:流动性系列-流动性清洗和反转、决策区间

MySQL master-slave synchronization
![Jerry's touch key recognition process [chapter]](/img/cf/8dacbb7f80e427276df6201dddd377.png)
Jerry's touch key recognition process [chapter]

NLP 论文领读|文本生成模型退化怎么办?SimCTG 告诉你答案

obsidian配合hugo的使用,让markdown本地编辑软件与在线化无缝衔接
随机推荐
Encoding type of Perl conversion file
25: Chapter 3: developing pass service: 8: [registration / login] interface: receiving and verifying "mobile number and verification code" parameters; (it is important to know the application scenario
谈谈内联函数
Taihu Lake "China's healthy agricultural products · mobile phone live broadcast" enters Taihu Lake
分析超700万个研发需求发现,这八大编程语言才是行业最需要的
项目经理不应该犯的错误
25:第三章:开发通行证服务:8:【注册/登录】接口:接收并校验“手机号和验证码”参数;(重点需要知道【利用redis来暂存数据,获取数据的】的应用场景)(使用到了【@Valid注解】参数校验)
第81场双周赛
数据库 OLAP、OLTP是什么?相同和不同?适用场景
杰理之触摸按键识别流程【篇】
obsidian配合hugo的使用,让markdown本地编辑软件与在线化无缝衔接
Qt和其它GUI库的对比
SecureCRTPortable的安装和使用(图文详解)
Build your own website (20)
AVL balanced binary tree (I) - concept and C language implementation
Wechat applet development practice cloud music
Jerry's touch key recognition process [chapter]
originpro 2021 附安装教程
杰理之触摸按键识别流程【篇】
CADD course learning (1) -- basic knowledge of drug design