druid图形化监控 + MyBatis优化器使用

文章目录

    • 1.集成druid图形化监控
        • 1.配置application.yml
        • 2.测试访问 http://localhost:项目端口/druid
    • 2.MyBatis优化器(显示完整sql)
        • 1.目录
        • 2.SqlBeautyInterceptor.java:sql拦截器
        • 3.MybatisConfiguration.java:将sql拦截器注入容器
        • 4.测试
        • 5.MyBatis优化器动态加载
          • 1.修改MybatisConfiguration.java的bean注入方式
          • 2.application.yml中配置启用sql优化器

1.集成druid图形化监控

1.配置application.yml
spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverusername: password: url: jdbc:mysql://bj--grp-.sql.tencentcdb.com:24169/sun_frame?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=falsetype: com.alibaba.druid.pool.DruidDataSource # druid连接池druid:initial-size: 20 # 初始化连接数min-idle: 20 # 最小空闲连接数max-active: 100 # 最大连接数max-wait: 60000 # 获取连接的最大等待时间# druid图形化界面stat-view-servlet:enabled: true # 是否启用url-pattern: /druid/* # 访问路径login-username: adminlogin-password: 123456filter:stat:enabled: truelog-slow-sql: true # 是否打印慢日志slow-sql-millis: 2000 # 慢日志阈值,2s
2.测试访问 http://localhost:项目端口/druid

CleanShot 2024-07-10 at 15.11.01@2x

CleanShot 2024-07-10 at 15.15.30@2x

2.MyBatis优化器(显示完整sql)

1.目录

CleanShot 2024-07-10 at 15.25.00@2x

2.SqlBeautyInterceptor.java:sql拦截器
package com.sunxiansheng.inteceptor;import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.defaults.DefaultSqlSession.StrictMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.lang.reflect.Field;
import java.sql.Statement;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;/*** SQL优化器:显示完整的SQL*/
@Intercepts({@Signature(type = StatementHandler.class, method = "query", args = {Statement.class, ResultHandler.class}),@Signature(type = StatementHandler.class, method = "update", args = {Statement.class}),@Signature(type = StatementHandler.class, method = "batch", args = {Statement.class})
})
public class SqlBeautyInterceptor implements Interceptor {private static final Logger logger = LoggerFactory.getLogger(SqlBeautyInterceptor.class);private static final Set<Class<?>> PRIMITIVE_WRAPPER_CLASSES = new HashSet<>(Arrays.asList(Byte.class, Short.class, Integer.class, Long.class, Double.class, Float.class, Character.class, Boolean.class));@Overridepublic Object intercept(Invocation invocation) throws Throwable {StatementHandler statementHandler = (StatementHandler) invocation.getTarget();long startTime = System.currentTimeMillis();try {return invocation.proceed();} finally {long endTime = System.currentTimeMillis();long sqlCost = endTime - startTime;BoundSql boundSql = statementHandler.getBoundSql();String sql = boundSql.getSql();Object parameterObject = boundSql.getParameterObject();List<ParameterMapping> parameterMappingList = boundSql.getParameterMappings();sql = formatSql(sql, parameterObject, parameterMappingList);sql = beautifySql(sql);logger.info("\n========================\nSQL:\n{}\n执行耗时: [{} ms]\n========================", sql, sqlCost);}}@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}@Overridepublic void setProperties(Properties properties) {}private String formatSql(String sql, Object parameterObject, List<ParameterMapping> parameterMappingList) {if (sql == null || sql.trim().isEmpty()) {return "";}sql = beautifySql(sql);if (parameterObject == null || parameterMappingList == null || parameterMappingList.isEmpty()) {return sql;}String sqlWithoutReplacePlaceholder = sql;try {if (isStrictMap(parameterObject.getClass())) {StrictMap<?> strictMap = (StrictMap<?>) parameterObject;if (isList(strictMap.get("list").getClass())) {sql = handleListParameter(sql, (List<?>) strictMap.get("list"));}} else if (isMap(parameterObject.getClass())) {sql = handleMapParameter(sql, (Map<?, ?>) parameterObject, parameterMappingList);} else {sql = handleCommonParameter(sql, parameterMappingList, parameterObject);}} catch (Exception e) {logger.error("Error formatting SQL: ", e);return sqlWithoutReplacePlaceholder;}return sql;}private String handleCommonParameter(String sql, List<ParameterMapping> parameterMappingList, Object parameterObject) throws Exception {Class<?> parameterObjectClass = parameterObject.getClass();List<Field> allFields = new ArrayList<>();while (parameterObjectClass != null) {allFields.addAll(Arrays.asList(parameterObjectClass.getDeclaredFields()));parameterObjectClass = parameterObjectClass.getSuperclass();}for (ParameterMapping parameterMapping : parameterMappingList) {String propertyValue;String propertyName = parameterMapping.getProperty();Field field = allFields.stream().filter(f -> f.getName().equals(propertyName)).findFirst().orElse(null);if (field != null) {field.setAccessible(true);propertyValue = String.valueOf(field.get(parameterObject));if (parameterMapping.getJavaType().isAssignableFrom(String.class)) {propertyValue = "\"" + propertyValue + "\"";}} else if (isPrimitiveOrPrimitiveWrapper(parameterObject.getClass())) {propertyValue = parameterObject.toString();} else {continue;}sql = sql.replaceFirst("\\?", Matcher.quoteReplacement(propertyValue));}return sql;}private String handleMapParameter(String sql, Map<?, ?> paramMap, List<ParameterMapping> parameterMappingList) {for (ParameterMapping parameterMapping : parameterMappingList) {Object propertyName = parameterMapping.getProperty();Object propertyValue = paramMap.get(propertyName);if (propertyValue != null) {if (propertyValue.getClass().isAssignableFrom(String.class)) {propertyValue = "\"" + propertyValue + "\"";}sql = sql.replaceFirst("\\?", Matcher.quoteReplacement(propertyValue.toString()));}}return sql;}private String handleListParameter(String sql, Collection<?> col) {if (col != null && !col.isEmpty()) {for (Object obj : col) {String value = obj.toString();if (obj.getClass().isAssignableFrom(String.class)) {value = "\"" + value + "\"";}sql = sql.replaceFirst("\\?", Matcher.quoteReplacement(value));}}return sql;}private String beautifySql(String sql) {// 移除多余的空白字符sql = sql.replaceAll("[\\s\n]+", " ").trim();// 格式化常见的SQL关键字和子句sql = sql.replaceAll("(?i)\\b(SELECT|INSERT INTO|UPDATE|DELETE FROM|FROM|WHERE|SET|VALUES|LEFT JOIN|RIGHT JOIN|INNER JOIN|OUTER JOIN|GROUP BY|ORDER BY|HAVING|LIMIT|OFFSET)\\b", "\n$1");// 处理 INSERT INTO 和 VALUES 语句以及括号格式sql = sql.replaceAll("(?i)\\b(INSERT INTO [^\\(]+\\()", "\n$1\n  ");sql = sql.replaceAll("(?i)\\b(VALUES)\\s*\\(", "\n$1\n  (");sql = sql.replaceFirst("\\)\\s*VALUES", "\n)\nVALUES");// 对 SQL 的各个部分进行缩进处理String[] lines = sql.split("\n");StringBuilder formattedSql = new StringBuilder();int indentLevel = 0;for (String line : lines) {if (line.matches("(?i)^\\s*(SELECT|INSERT INTO|UPDATE|DELETE FROM|FROM|WHERE|SET|VALUES|LEFT JOIN|RIGHT JOIN|INNER JOIN|OUTER JOIN|GROUP BY|ORDER BY|HAVING|LIMIT|OFFSET)\\b.*")) {if (line.matches("(?i)^\\s*(FROM|WHERE|SET|VALUES|LEFT JOIN|RIGHT JOIN|INNER JOIN|OUTER JOIN|GROUP BY|ORDER BY|HAVING|LIMIT|OFFSET)\\b.*")) {indentLevel--;}formattedSql.append(repeat("  ", indentLevel)).append(line.trim()).append("\n");if (line.matches("(?i)^\\s*(SELECT|INSERT INTO|UPDATE|DELETE FROM)\\b.*")) {indentLevel++;}} else {formattedSql.append(repeat("  ", indentLevel)).append(line.trim()).append("\n");}}// 特殊处理闭括号使其位于新行formattedSql = new StringBuilder(formattedSql.toString().replace(") VALUES", "\n) VALUES"));formattedSql = new StringBuilder(formattedSql.toString().replaceAll("\\),", "\n),"));return formattedSql.toString().trim();}private String formatValues(String sql) {Pattern pattern = Pattern.compile("(?i)(VALUES\\s*\\(([^\\)]+)\\))");Matcher matcher = pattern.matcher(sql);StringBuffer sb = new StringBuffer();while (matcher.find()) {String group = matcher.group(2);String[] values = group.split(",");StringBuilder sbGroup = new StringBuilder();sbGroup.append("VALUES (\n  ");for (String value : values) {sbGroup.append(value.trim()).append(", ");}sbGroup.setLength(sbGroup.length() - 2); // 移除最后一个逗号和空格sbGroup.append("\n)");matcher.appendReplacement(sb, sbGroup.toString());}matcher.appendTail(sb);return sb.toString();}private String repeat(String str, int count) {StringBuilder result = new StringBuilder();for (int i = 0; i < count; i++) {result.append(str);}return result.toString();}private boolean isPrimitiveOrPrimitiveWrapper(Class<?> clazz) {return clazz.isPrimitive() || PRIMITIVE_WRAPPER_CLASSES.contains(clazz);}private boolean isStrictMap(Class<?> clazz) {return StrictMap.class.isAssignableFrom(clazz);}private boolean isList(Class<?> clazz) {return List.class.isAssignableFrom(clazz);}private boolean isMap(Class<?> clazz) {return Map.class.isAssignableFrom(clazz);}
}
3.MybatisConfiguration.java:将sql拦截器注入容器
import com.sunxiansheng.inteceptor.SqlBeautyInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** MyBatis配置类:用于将Bean注入容器*/
@Configuration
public class MybatisConfiguration {// 注入Bean容器@Beanpublic SqlBeautyInterceptor sqlBeautyInterceptor() {return new SqlBeautyInterceptor();}
}
4.测试

CleanShot 2024-07-10 at 16.05.31@2x

5.MyBatis优化器动态加载
1.修改MybatisConfiguration.java的bean注入方式
package com.sunxiansheng.config;import com.sunxiansheng.inteceptor.SqlBeautyInterceptor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** MyBatis配置类:用于将Bean注入容器*/
@Configuration
public class MybatisConfiguration {// 注入Bean容器@Bean// 只有当 sql.beauty.show 的值为 "true" 时,相关的配置或 bean 才会被注册。// matchIfMissing: 如果设置为 true,这意味着如果在配置中没有找到 name 指定的属性,则条件视为匹配。@ConditionalOnProperty(name = {"sql.beauty.show"}, havingValue = "true", matchIfMissing = true)public SqlBeautyInterceptor sqlBeautyInterceptor() {System.out.println();return new SqlBeautyInterceptor();}
}

CleanShot 2024-07-10 at 16.24.56@2x

2.application.yml中配置启用sql优化器

CleanShot 2024-07-10 at 16.25.22@2x

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/490972.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【经验分享】私有云运维的知识点

最近忙于备考没关注&#xff0c;有次点进某小黄鱼发现首页出现了我的笔记还被人收费了 虽然我也卖了一些资源&#xff0c;但我以交流、交换为主&#xff0c;笔记都是免费给别人看的 由于当时刚刚接触写的并不成熟&#xff0c;为了避免更多人花没必要的钱&#xff0c;所以决定公…

Unity 2020、2021、2022、2023、6000下载安装

Unity 2020、2021、2022、2023、6000 下载安装 以Unity 6000.0.24fc1下载安装为例&#xff1a; 打开 https://unity.cn/ 优三缔 官方网站&#xff1b; 点击【产品列表】→点击【查看更多】→选择自己需要的版本→点【开始使用】 点击【从Unity Hub下载】 以Windows为例&am…

240004】基于maven的java+ssm+mysql的房屋租赁系统的设计与实现

基于ssmmavenmysql的房屋租赁系统的设计与实现 1.项目描述2.运行环境3.项目截图4.源码获取 1.项目描述 该项目在原有的基础上进行了优化&#xff0c;包括新增了注册功能&#xff0c;房屋模糊查询功能&#xff0c;管理员和用户信息管理等功能&#xff0c;以及对网站界面进行了优…

NEEP-EN2-2023-Section5PartB

题目 个人答案 The chart depicts the outcomes of a survey conducted in a specific university regarding the acquisition of practical activity in class. The chart illustrates that learning knowledges accounts for 91.3 percent, which is the highest percentage…

WPF 控件

<div id"content_views" class"htmledit_views"><p id"main-toc"><strong>目录</strong></p> WPF基础控件 按钮控件&#xff1a; Button:按钮 RepeatButton:长按按钮 RadioButton:单选按钮 数据显示控件 Te…

系列1:基于Centos-8.6部署Kubernetes (1.24-1.30)

每日禅语 “木末芙蓉花&#xff0c;山中发红萼&#xff0c;涧户寂无人&#xff0c;纷纷开自落。​”这是王维的一首诗&#xff0c;名叫《辛夷坞》​。这首诗写的是在辛夷坞这个幽深的山谷里&#xff0c;辛夷花自开自落&#xff0c;平淡得很&#xff0c;既没有生的喜悦&#xff…

ESP8266 Ubuntu 安装

文章参考&#xff1a;https://blog.csdn.net/AUST_129/article/details/119406722文章浏览阅读1.8k次&#xff0c;点赞4次&#xff0c;收藏19次。参考&#xff1a;https://docs.espressif.com/projects/esp8266-rtos-sdk/en/latest/get-started/linux-setup.htmlhttp://aicloud…

软件压力测试和负载测试有什么联系与区别?

在当今数字化时代&#xff0c;软件质量的重要性愈发凸显。在各种软件测试中&#xff0c;压力测试和负载测试都属于性能测试中的一种测试方法&#xff0c;那么这两者分别是什么?又有什么联系和区别呢? 一、压力测试和负载测试的定义   压力测试通常是指在特定的环境中&…

C# 异常处理 详解

总目录 前言 一、异常 1、定义 异常是在程序执行期间出现的问题。 C# 中的异常是对程序运行时出现的特殊情况的一种响应&#xff0c;比如尝试除以零。 异常&#xff1a;程序员必须控制和解决的问题。程序可以正常的运行&#xff0c;但是在运行的过程中出现了问题&#xff0c;…

类OCSP靶场-Kioptrix系列-Kioptrix Level 2

一、前情提要 二、实战打靶 1. 信息收集 1.1. 主机发现 1.2. 端口扫描 1.3.目录遍历 2.漏洞发现 2.1. 登录框测试 2.2. 发现命令执行 2.3 构造命令执行利用payload 3.提权 3.1. 搜索提权exp 3.2. 查看exp信息 3.3. Privilege Escalation的exp利用 exp_9542 一、前…

μC/OS-Ⅱ源码学习(6)---事件标志组

快速回顾 μC/OS-Ⅱ中的多任务 μC/OS-Ⅱ源码学习(1)---多任务系统的实现 μC/OS-Ⅱ源码学习(2)---多任务系统的实现(下) μC/OS-Ⅱ源码学习(3)---事件模型 μC/OS-Ⅱ源码学习(4)---信号量 μC/OS-Ⅱ源码学习(5)---消息队列 本文进一步解析事件模型中&#xff0c;事件标志…

学习maven(maven 项目模块化,继承,聚合)

前言 本篇博客的核心&#xff1a;理解maven 项目模块化&#xff0c;继承&#xff0c;聚合 的含义 maven 项目模块化 含义 maven项目模块化&#xff1a;使用maven 构建项目&#xff0c;管理项目的方式&#xff0c;我们可以将maven项目根据内在的关系拆分成很多个小项目【模块】…

电工电子技术实验:电压比较器及其应用电路

实验目的 1&#xff0e;了解电压比较器与运算放大器的性能区别&#xff1b; 2&#xff0e;掌握电压比较器的结构及特点&#xff1b; 3&#xff0e;掌握电压比较器电压传输特性的测试方法&#xff1b; 4&#xff0e;学习比较器在电路设计中的应用 实验原理 电压比较器是一…

3D相框案例讲解(详细)

前言 通过现阶段的学习&#xff0c;我们已经掌握了HTML&#xff0c;CSS和JS部分的相关知识点&#xff0c;现在让我们通过一篇案例&#xff0c;来巩固我们近期所学的知识点。 详细视频讲解戳这里 任务一 了解目标案例样式 1.1了解案例 3D相框 1.2 分析案例 首先我们看到一个…

C/C++代码性能优化技巧的书籍及资料

使用C/C开发的场景&#xff0c;大多对代码的执行的速度&#xff0c;实时性有较高的要求&#xff0c;像嵌入式系统的开发&#xff0c;资源还受限。在算力存储空间有限的MCU上写出简洁又高效的代码实际是一种艺术。软件工程师在代码设计上的这种差距&#xff0c;会反映在产品的性…

JAVA:建造者模式(Builder Pattern)的技术指南

1、简述 建造者模式(Builder Pattern)是一种创建型设计模式,它通过将对象的构造过程与表示分离,使得相同的构造过程可以创建不同的表示。建造者模式尤其适用于创建复杂对象的场景。 设计模式样例:https://gitee.com/lhdxhl/design-pattern-example.git 本文将详细介绍建…

软件集成测试内容和作用简析

在现代软件开发过程中&#xff0c;软件集成测试作为关键的一环&#xff0c;日益受到重视。特别是随着信息技术的快速发展&#xff0c;各类软件系统日益庞大复杂&#xff0c;如何确保系统不同模块的顺畅合作&#xff0c;成为了每个项目成功的重要基础。集成测试是指在软件开发过…

Windows 环境实战开源项目GFPGAN 教程

GFPGAN GFPGAN&#xff08;Generative Facial Prior-GAN&#xff09;是由腾讯ARC&#xff08;Applied Research Center&#xff09;开发的一种实用的真实世界人脸修复算法。它专门设计用于人脸图像的生成和优化&#xff0c;尤其在低质量人脸图像的超分辨率恢复方面表现出色。以…

ctfshow xss

1.web316 看的wp 先在服务器上写一个php文件 <?php$cookie $_GET[cookie];$time date(Y-m-d h:i:s, time());$log fopen("cookie.txt", "a");fwrite($log,$time.: . $cookie . "\n");fclose($log); ?> 获取cookie的值&#xff…

25. 深浅拷贝

一、什么是浅拷贝 只对对象的最顶层进行的拷贝称为 浅拷贝。我们可以用 copy 模块中的 copy() 方法实现浅拷贝。 import copya [11, 22, 33] b [44, 55, 66] c [a, b] d copy.copy(c)print(f"c: {c}") print(f"d: {d}") print(f"c d: {c d}&q…