当前位置:网站首页>jfinal中如何使用过滤器监控Druid监听SQL执行?
jfinal中如何使用过滤器监控Druid监听SQL执行?
2022-06-29 21:35: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修改逻辑,比如添加数据权限等等。
边栏推荐
- Small library project summary
- 炒股开户请问哪个券商佣金是最低最安全的
- 不同系统下的文件层级符号小结
- If the evaluation conclusion of waiting insurance is poor, does it mean that waiting insurance has been done in vain?
- STM32最小系统搭建(原理图)
- leetcode:307. Area and retrieval - array modifiable
- yolov6训练自己的数据记录+yolov5对比测试
- Add the applet "lazycodeloading": "requiredcomponents" in taro,
- My creation anniversary
- The inadvertently discovered [tidb cache table] can solve the read / write hotspot problem
猜你喜欢

ASP动态创建表格 Table

Hardware development notes (VIII): basic process of hardware development, making a USB to RS232 module (VII): creating a basic dip component (crystal oscillator) package and associating the principle

Autodesk Revit 2023 software installation package download and installation tutorial

Knowledge distilling learning notes

Realization of graduation project topic selection system based on JSP

Reading notes on how to connect the network - LAN on the server side (4)

STM32 minimum system construction (schematic diagram)

每周招聘|DBA数据工程师,年薪35+ ,梦起九州,星河灿烂!

CLI tool foundation of ros2 robot f1tenth

【ROS进阶篇】第四讲 ROS中的重名问题(节点、话题与参数)
随机推荐
唯品会商品详情API接口(item_get-获得唯品会商品详情接口),唯品会详情API接口
About Effect Size
MES系统与ERP如何集成?本文告诉你答案
Report delivery engineer
CSDN failed to replicate problem
A. Print a Pedestal (Codeforces logo?)
Change detection and batch update
小型图书馆项目总结
How to use SMS to deliver service information to customers? The guide is here!
Realization of graduation project topic selection system based on JSP
Layer 3 loop brought by route Summary - solution experiment
透过华为军团看科技之变(五):智慧园区
Which brokerage commission is the lowest and safest
证券开户选择哪个证券另外想问,现在在线开户安全么?
cout 不明确问题
高校如何基于云原生构建面向未来的智慧校园?全栈云原生VS传统技术架构
A keepalived high availability accident made me learn it again!
The explain function of the DALEX package of R language generates a machine learning model interpreter and predict for the specified classification prediction_ The parts function analyzes the contribu
Design of VHDL telephone billing system
Recommended books -- walking in the daytime and at night