当前位置:网站首页>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修改逻辑,比如添加数据权限等等。
边栏推荐
- CLI tool foundation of ros2 robot f1tenth
- A. Beat The Odds
- STM32 and gd32 notes
- Which brokerage commission is the lowest and safest
- How to prepare samples for application of color coated steel sealing plates to BS 476-3?
- 铝板AS/NZS 1530.1 不燃性材料的阻燃测试
- 证券开户选择哪个证券另外想问,现在在线开户安全么?
- STM32最小系统搭建(原理图)
- MES系统与ERP如何集成?本文告诉你答案
- Implementing LDAP proxy service with haproxy + keepalive
猜你喜欢

Water polo chart - using dynamic ripples to show percentages

小型图书馆项目总结

JD alliance API - universal chain transfer interface - Jingpin library interface - Interface Customization

小型圖書館項目總結

Yolov6 training your own data record +yolov5 comparison test

PostgreSQL每周新闻—6月22日

cout 不明确问题

ASP动态创建表格 Table

Sophon CE community edition goes online, and free get is a lightweight, easy-to-use, efficient and intelligent data analysis tool

ASP. Net cross page submission (button control page redirection)
随机推荐
美国隧道法ASTM E84 表面阻燃测试
Matlab output format control%d,%f,%c,%s usage
LeetCode 1. 两数之和
As a developer, you need to know about the codeless development platform IVX
A new Polaris has risen!
Layer 3 loop brought by route Summary - solution experiment
Shell implementation of Memcache cache cache hit rate monitoring script
状态管理 利用Session限制页面访问 只有通过登录验证SessionLogin.aspx才能访问Session.aspx
Implementation and Simulation of ads131a04 ADC Verilog
Verilog realizes serial communication and sends it to the nixie tube
Shutter bottomnavigationbar with page switching example
Is it safe to open a securities account in Caixue school?
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
DB queries the database, merges two unrelated tables, adds non-existent fields, and assigns default values
Digital password lock Verilog design + simulation + on board verification
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
亚马逊关键词搜索API接口(item_search-按关键字搜索亚马逊商品接口),亚马逊API接口
How to make good use of data science?
Taro2.* applet configuration sharing wechat circle of friends
If the evaluation conclusion of waiting insurance is poor, does it mean that waiting insurance has been done in vain?