基于JRebel开发的MySQL Explain插件
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了基于JRebel开发的MySQL Explain插件,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含7581字,纯文字阅读大概需要11分钟。
内容图文
mysql--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> <scope>runtime</scope> </dependency> 执行SQL时,经过跟踪代码执行路径,最终会到达这个方法:com.mysql.jdbc.PreparedStatement#executeInternal/** * 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 {}其中,参数sendPacket就是最终要执行的完整sql语句。我们需要在这个方法中加入explain sql逻辑。
实现
我们所写的插件应该是通用的,不能侵入现有代码。不限于以下两种实现方式:- javaagent -- 相对复杂一点,但是很通用,无特殊依赖
- jrebel自定义插件 -- 需要安装jrebel插件,idea和eclipse均支持
1. 新建一个maven项目
pom依赖如下:<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>View Code
2. 编写jrebel CBP
继承org.zeroturnaround.javarebel.integration.support.JavassistClassBytecodeProcessorpackage 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);" ); } }View Code
3. 自定义explain逻辑
查看MySQL执行计划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); } }View Code
4. 编写jrebel插件入口类
实现接口:org.zeroturnaround.javarebel.Plugin,需在pom中配置该类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即可 }View Code
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>View Code
6. 打包
mvn clean package -Dmaven.test.skip=true
7. 使用该插件
项目需要使用jrebel启动,并且指定该插件所在路径,通过jvm参数指定-Drebel.plugins=/your/path/mysql-explain-jr-plugin.jar若生效,控制台会输出“MySQLExplainCBP...”等字样。
8 演示效果
此处加了一些自定义逻辑- 启动时输出MySQL执行计划配置:
- 执行计划打印示例:
总结
基本实现了功能,可以结合idea插件达到更加便捷友好的使用体验!项目地址
暂无,稍后补充参考
Custom JRebel plugins
内容总结
以上是互联网集市为您收集整理的基于JRebel开发的MySQL Explain插件全部内容,希望文章能够帮你解决基于JRebel开发的MySQL Explain插件所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。