基于JRebel开发的MySQL Explain插件
前言
探索
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
<scope>runtime</scope>
</dependency>
/**
* Actually execute the prepared statement. This is here so server-side
* PreparedStatements can re-use most of the code from this class.
*
* @param maxRowsToRetrieve the max number of rows to return
* @param sendPacket SQL语句packet
* @param createStreamingResultSet should a 'streaming' result set be created?
* @param queryIsSelectOnly is this query doing a SELECT?
*/
protected ResultSetInternalMethods executeInternal(int maxRowsToRetrieve, Buffer sendPacket, boolean createStreamingResultSet, boolean queryIsSelectOnly,
Field[] metadataFromCache, boolean isBatch) throws SQLException {}
实现
- javaagent -- 相对复杂一点,但是很通用,无特殊依赖
- jrebel自定义插件 -- 需要安装jrebel插件,idea和eclipse均支持
1. 新建一个maven项目
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<sdk.version>7.0.0</sdk.version>
</properties> <repositories>
<repository>
<id>zt-public</id>
<url>https://repos.zeroturnaround.com/nexus/content/groups/zt-public</url>
</repository>
</repositories> <dependencies>
<dependency>
<groupId>org.zeroturnaround</groupId>
<artifactId>jr-sdk</artifactId>
<version>${sdk.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.zeroturnaround</groupId>
<artifactId>jr-utils</artifactId>
<version>${sdk.version}</version>
<scope>provided</scope>
</dependency> <dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
<scope>provided</scope>
</dependency>
</dependencies>
2. 编写jrebel CBP
package com.example.plugin.mysql.cbp;
public class MySQLExplainCBP extends JavassistClassBytecodeProcessor {
@Override
public void process(ClassPool cp, ClassLoader cl, CtClass ctClass) throws Exception {
LoggerFactory.getInstance().echo("MySQLExplainCBP...");
// 自定义处理类所在包
cp.importPackage("com.example.plugin.mysql.explain");
// 找到方法:com.mysql.jdbc.PreparedStatement#executeInternal
// 在该方法第一行之前插入自定义逻辑
CtMethod m = ctClass.getDeclaredMethod("executeInternal");
m.insertBefore(
"MySQLExplain.explainSql(this.connection, sendPacket);"
);
}
}
3. 自定义explain逻辑
package com.example.plugin.mysql.explain;
public final class MySQLExplain {
private static final Logger logger = LoggerFactory.getInstance();
/**
* 调用者:MySQLExplainCBP#process
*/
public static void explainSql(com.mysql.jdbc.MySQLConnection conn, com.mysql.jdbc.Buffer sendPacket) {
byte[] bytes = new byte[sendPacket.getPosition()];
System.arraycopy(sendPacket.getByteBuffer(), 0, bytes, 0, bytes.length);
String sql = new String(bytes, 5, bytes.length - 5);
// 前置检查,检查是否执行计划
if (!processBefore(sql)) {
return;
}
try {
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("EXPLAIN " + sql);
List<ExplainResultVo> explainResultList = new ArrayList<>();
while (rs.next()) {
ExplainResultVo explainResultVo = new ExplainResultVo();
explainResultVo.setId(rs.getString("id"));
explainResultVo.setSelectType(rs.getString("select_type"));
explainResultVo.setTable(rs.getString("table"));
explainResultVo.setPartitions(rs.getString("partitions"));
explainResultVo.setType(rs.getString("type"));
explainResultVo.setPossibleKeys(rs.getString("possible_keys"));
explainResultVo.setKey(rs.getString("key"));
explainResultVo.setKeyLen(rs.getString("key_len"));
explainResultVo.setRef(rs.getString("ref"));
explainResultVo.setRows(rs.getString("rows"));
explainResultVo.setFiltered(rs.getString("filtered"));
explainResultVo.setExtra(rs.getString("Extra"));
explainResultList.add(explainResultVo);
}
rs.close();
// 打印结果
analyzeResult(sql, explainResultList);
} catch (Exception se) {
logger.errorEcho("EXPLAIN SQL异常", se);
}
}
/**
* 前置检查,检查是否执行计划,自定添加逻辑
*/
private static boolean processBefore(String sql) {
return true;
}
/**
* 分析结果,打印执行计划,可自定添加过滤条件
*/
private static void analyzeResult(String sql, List<ExplainResultVo> explainResultList) {
ExplainHelper.printExplainResult(sql, explainResultList, showSQL);
}
}
4. 编写jrebel插件入口类
package com.example.plugin.mysql; /**
* 插件注册,需在pom中配置该类
*/
public class MySQLExplainPlugin implements Plugin {
private static final Logger logger = LoggerFactory.getInstance(); @Override
public void preinit() {
Integration integration = IntegrationFactory.getInstance();
ClassLoader cl = getClass().getClassLoader(); logger.echo("MySQL执行计划插件启用, 配置详情: \n" + Config.getMySQLConfTable());
integration.addIntegrationProcessor(
cl,
"com.mysql.jdbc.PreparedStatement",
new MySQLExplainCBP());
} // 指定依赖条件,依赖存在时才启用本插件
@Override
public boolean checkDependencies(ClassLoader cl, ClassResourceSource crs) {
return crs.getClassResource("com.mysql.jdbc.PreparedStatement") != null;
} @Override
public String getId() {
return "mysql-explain-jr-plugin";
} // 省略其余方法,默认返回null即可
}
5. 在pom中指定插件入口类
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
<configuration>
<archive>
<manifestEntries>
<JavaRebel-Plugin>com.example.plugin.mysql.MySQLExplainPlugin</JavaRebel-Plugin>
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
</build>
6. 打包
mvn clean package -Dmaven.test.skip=true
7. 使用该插件
-Drebel.plugins=/your/path/mysql-explain-jr-plugin.jar
8 演示效果
- 启动时输出MySQL执行计划配置:

- 执行计划打印示例:

总结
项目地址
参考
基于JRebel开发的MySQL Explain插件的更多相关文章
- 基于JRebel开发的MybatisPlus热加载插件
前言 前天项目中使用了mybatis-plus,但是搭配Jrebel开发项目时,发现修改mapper的xml,或者mapper方法中的注解,Jrebel并没有能够reload mapper.于是就有了 ...
- 手把手教你基于C#开发WinCC语音报警插件「附源代码」
写在前面 众所周知,WinCC本身是可以利用C脚本或者VBS脚本来做语音报警,但是这种方式的本质是调用已存在的音频文件,想要实现实时播报报警信息是不行的,灵活性还不够,本文主要介绍基于C#/.NET开 ...
- 一些基于jQuery开发的控件
基于jQuery开发,非常简单的水平方向折叠控件.主页:http://letmehaveblog.blogspot.com/2007/10/haccordion-simple-horizontal-a ...
- 「完整案例」基于Socket开发TCP传输客户端
1 程序界面设计 TCP客户端在上位机开发中应用很广,大多数情况下,上位机软件都是作为一个TCP客户端来与PLC或其他服务器进行通信的.TCP客户端的主要功能就是连接服务器.发送数据.接收数据.断开 ...
- mac 下基于firebreath 开发多浏览器支持的浏览器插件
mac 下基于firebreath 开发多浏览器支持的浏览器插件 首先要区分什么是浏览器扩展和浏览器插件;插件可以像本地程序一样做的更多 一. 关于 firebreath http://www.fir ...
- Mysql Explain 解读(基于MySQL 5.6.36)
Mysql Explain 解读(基于MySQL 5.6.36) 1.语法 explain < table_name > #例子 explain select * from t3 wher ...
- Dropdown.js基于jQuery开发的轻量级下拉框插件
Dropdown.js 前言 在SPA(Single Page Application)盛行的时代,jQuery插件的轮子正在减少,由于我厂有需求而开发了这个插件.如果觉得本文对您有帮助,请给个赞,以 ...
- PostgreSQL 优势,MySQL 数据库自身的特性并不十分丰富,触发器和存储过程的支持较弱,Greenplum、AWS 的 Redshift 等都是基于 PostgreSQL 开发的
PostgreSQL 优势 2016-10-20 21:36 686人阅读 评论(0) 收藏 举报 分类: MYSQL数据库(5) PostgreSQL 是一个自由的对象-关系数据库服务器(数据库 ...
- 基于gin的golang web开发:mysql增删改查
Go语言访问mysql数据库需要用到标准库database/sql和mysql的驱动.标准库的Api使用比较繁琐这里再引入另一个库github.com/jmoiron/sqlx. go get git ...
随机推荐
- difflib python
difflib -帮助进行差异化比较 这个模块提供的类和方法用来进行差异化比较,它能够生成文本或者html格式的差异化比较结果,如果需要比较目录的不同,可以使用filecmp模块. 例子: # -*- ...
- codeforces 339A.Helpful Maths B.Xenia and Ringroad 两水题
A.题意就是把字符串里面的数字按增序排列,直接上代码. #include <string.h> #include <stdio.h> #include <algorith ...
- Python开发异步任务Celery的使用教程!
1. 生产者消费者设计模式 最常用的解耦方式之一,寻找中间人(broker)搭桥,保证两个业务没有直接关联.我们称这一解耦方式为:生产者消费者设计模式 2.中间人broker 示例:此处演示Redis ...
- Ubuntu 磁盘挂载错误
一.错误 报错原因: 在删除或者复制移动时,磁盘或者u盘等外接硬件设备,忽然掉落(断掉,接口松动),在次挂载磁盘时就会出现错误 错误日志: $MFTMirr does not match $MFT ( ...
- 一份新的lilypond谱子,能设置页边距和设置换页符了
给学生做的一份乐谱,这回能设置页边距了,以及设置换页符了. 顺带能设置一些代码片段(snippet),可以用热键代替使用 设置页边距的snippet: \paper { %双引号里面填页面大小 #(s ...
- Angualr6表单提交验证并跳转
在Angular6中,使用NG-ZRROR作为前端开发框架,在进行表单开发时遇到了一些问题,最后解决了,在此记录. 1.表单构造: 引入forms: import { FormGroup, FormB ...
- Kalman Filter、Extended Kalman Filter以及Unscented Kalman Filter介绍
模型定义 如上图所示,卡尔曼滤波(Kalman Filter)的基本模型和隐马尔可夫模型类似,不同的是隐马尔科夫模型考虑离散的状态空间,而卡尔曼滤波的状态空间以及观测空间都是连续的,并且都属于高斯分布 ...
- oracle 正确删除归档日志,并清除 V$ARCHIVED_LOG 数据
1. 连接 RMAN 管理 rman target / 2. 查看归档日志列表 RMAN> crosscheck archivelog all; 3. 删除所有归档日志 RMAN> DEL ...
- JavaScript数据结构——树的实现
在计算机科学中,树是一种十分重要的数据结构.树被描述为一种分层数据抽象模型,常用来描述数据间的层级关系和组织结构.树也是一种非顺序的数据结构.下图展示了树的定义: 在介绍如何用JavaScript实现 ...
- Netty基础系列(4) --堆外内存与零拷贝详解
前言 到目前为止,我们知道Nio当中有三个最最核心的组件,分别是:Selelctor,Channel,Buffer.在Netty基础系列(3) --彻底理解NIO 这一篇文章中只是进行了大致的介绍. ...