diff --git a/README.md b/README.md
index a62239d14..f31c02b89 100644
--- a/README.md
+++ b/README.md
@@ -58,7 +58,7 @@ Topiam IAM/IDaaS身份管理平台 - https://www.topiam.cn/
| Redis客户端 | 采用 Redisson Redis官方推荐 基于Netty的客户端工具
支持Redis 90%以上的命令 底层优化规避很多不正确的用法 例如: keys被转换为scan
支持单机、哨兵、单主集群、多主集群等模式 | Lettuce + RedisTemplate 支持模式少 工具使用繁琐
连接池采用 common-pool Bug多经常性出问题 |
| 缓存注解 | 采用 Spring-Cache 注解 对其扩展了实现支持了更多功能
例如 过期时间 最大空闲时间 组最大长度等 只需一个注解即可完成数据自动缓存 | 需手动编写Redis代码逻辑 |
| ORM框架 | 采用 Mybatis-Plus 基于对象几乎不用写SQL全java操作 功能强大插件众多
例如分页插件 乐观锁插件等等 | 采用 Mybatis 基于XML需要手写SQL |
-| SQL监控 | 采用 p6spy 可输出完整SQL与执行时间监控 | log输出 需手动拼接sql与参数无法快速查看调试问题 |
+| SQL监控 | 内置 MyBatis 完整 SQL 输出工具,可输出完整SQL、Mapper ID与执行时间监控 | log输出 需手动拼接sql与参数无法快速查看调试问题 |
| 数据分页 | 采用 Mybatis-Plus 分页插件
框架对其进行了扩展 对象化分页对象 支持多种方式传参 支持前端多排序 复杂排序 | 采用 PageHelper 仅支持单查询分页 参数只能从param传 只能单排序 功能扩展性差 体验不好 |
| 数据权限 | 采用 Mybatis-Plus 插件 自行分析拼接SQL 无感式过滤
只需为Mapper设置好注解条件 支持多种自定义 不限于部门角色 | 采用 注解+aop 实现 基于部门角色 生成的sql兼容性差 不支持其他业务扩展
生成sql后需手动拼接到具体业务sql上 对于多个Mapper查询不起作用 |
| 数据脱敏 | 采用 注解 + jackson 序列化期间脱敏 支持不同模块不同的脱敏条件
支持多种策略 如身份证、手机号、地址、邮箱、银行卡等 可自行扩展 | 无 |
diff --git a/pom.xml b/pom.xml
index 65bf1b477..48fd0963c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -30,7 +30,6 @@
3.5.16
1.5.7
4.5.0
- 3.9.1
8.7.3-20260306
3.0.2
7.17.28
@@ -242,13 +241,6 @@
${mybatis-plus-join.version}
-
-
- p6spy
- p6spy
- ${p6spy.version}
-
-
software.amazon.awssdk
diff --git a/ruoyi-admin/src/main/resources/application-dev.yml b/ruoyi-admin/src/main/resources/application-dev.yml
index bdd5c3f86..90173874c 100644
--- a/ruoyi-admin/src/main/resources/application-dev.yml
+++ b/ruoyi-admin/src/main/resources/application-dev.yml
@@ -61,14 +61,20 @@ snail-ai:
read-timeout-ms: 60000
chat-timeout-ms: 300000
+--- # MyBatis Plus 配置
+mybatis-plus:
+ sql-log:
+ # 完整 SQL 输出开关
+ enabled: true
+ # 输出方式,可选 console、log
+ output: console
+
--- # 数据源配置
spring:
datasource:
type: com.zaxxer.hikari.HikariDataSource
# 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content
dynamic:
- # 性能分析插件(有性能损耗 不建议生产环境使用)
- p6spy: true
# 设置默认的数据源或者数据源组,默认值即为 master
primary: master
# 严格模式 匹配不到数据源则报错
diff --git a/ruoyi-admin/src/main/resources/application-prod.yml b/ruoyi-admin/src/main/resources/application-prod.yml
index cbecae3e4..5c95799cb 100644
--- a/ruoyi-admin/src/main/resources/application-prod.yml
+++ b/ruoyi-admin/src/main/resources/application-prod.yml
@@ -64,14 +64,20 @@ snail-ai:
read-timeout-ms: 60000
chat-timeout-ms: 300000
+--- # MyBatis Plus 配置
+mybatis-plus:
+ sql-log:
+ # 完整 SQL 输出开关
+ enabled: false
+ # 输出方式,可选 console、log
+ output: console
+
--- # 数据源配置
spring:
datasource:
type: com.zaxxer.hikari.HikariDataSource
# 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content
dynamic:
- # 性能分析插件(有性能损耗 不建议生产环境使用)
- p6spy: false
# 设置默认的数据源或者数据源组,默认值即为 master
primary: master
# 严格模式 匹配不到数据源则报错
diff --git a/ruoyi-common/ruoyi-common-mybatis/pom.xml b/ruoyi-common/ruoyi-common-mybatis/pom.xml
index f2bf5d8c9..af3e623f1 100644
--- a/ruoyi-common/ruoyi-common-mybatis/pom.xml
+++ b/ruoyi-common/ruoyi-common-mybatis/pom.xml
@@ -58,11 +58,6 @@
mybatis-plus-join-boot-starter
-
-
- p6spy
- p6spy
-
diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/config/MybatisPlusConfig.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/config/MybatisPlusConfig.java
index 9b1a610c6..36992b4f3 100644
--- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/config/MybatisPlusConfig.java
+++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/config/MybatisPlusConfig.java
@@ -10,12 +10,16 @@ import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInt
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.dromara.common.core.factory.YmlPropertySourceFactory;
import org.dromara.common.mybatis.aspect.DataPermissionPointcutAdvisor;
+import org.dromara.common.mybatis.config.properties.SqlLogProperties;
import org.dromara.common.mybatis.handler.InjectionMetaObjectHandler;
import org.dromara.common.mybatis.handler.MybatisExceptionHandler;
import org.dromara.common.mybatis.handler.PlusPostInitTableInfoHandler;
import org.dromara.common.mybatis.interceptor.PlusDataPermissionInterceptor;
+import org.dromara.common.mybatis.interceptor.SqlLogInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.Role;
@@ -30,6 +34,7 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
@EnableTransactionManagement(proxyTargetClass = true)
@MapperScan("${mybatis-plus.mapperPackage}")
@PropertySource(value = "classpath:common-mybatis.yml", factory = YmlPropertySourceFactory.class)
+@EnableConfigurationProperties(SqlLogProperties.class)
public class MybatisPlusConfig {
/**
@@ -82,6 +87,15 @@ public class MybatisPlusConfig {
return new OptimisticLockerInnerInterceptor();
}
+ /**
+ * 完整 SQL 日志拦截器
+ */
+ @Bean
+ @ConditionalOnProperty(prefix = "mybatis-plus.sql-log", name = "enabled", havingValue = "true")
+ public SqlLogInterceptor sqlLogInterceptor(SqlLogProperties sqlLogProperties) {
+ return new SqlLogInterceptor(sqlLogProperties);
+ }
+
/**
* 元对象字段填充控制器
*/
diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/config/properties/SqlLogProperties.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/config/properties/SqlLogProperties.java
new file mode 100644
index 000000000..fe07f0105
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/config/properties/SqlLogProperties.java
@@ -0,0 +1,25 @@
+package org.dromara.common.mybatis.config.properties;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * SQL 日志配置。
+ *
+ * @author Lion Li
+ */
+@Data
+@ConfigurationProperties(prefix = "mybatis-plus.sql-log")
+public class SqlLogProperties {
+
+ /**
+ * 是否开启完整 SQL 输出。
+ */
+ private Boolean enabled = false;
+
+ /**
+ * 输出方式,可选 console、log。
+ */
+ private String output = "console";
+
+}
diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/interceptor/SqlLogInterceptor.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/interceptor/SqlLogInterceptor.java
new file mode 100644
index 000000000..6470860af
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/interceptor/SqlLogInterceptor.java
@@ -0,0 +1,361 @@
+package org.dromara.common.mybatis.interceptor;
+
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.ibatis.executor.statement.StatementHandler;
+import org.apache.ibatis.mapping.BoundSql;
+import org.apache.ibatis.mapping.MappedStatement;
+import org.apache.ibatis.mapping.ParameterMapping;
+import org.apache.ibatis.mapping.ParameterMode;
+import org.apache.ibatis.plugin.Interceptor;
+import org.apache.ibatis.plugin.Intercepts;
+import org.apache.ibatis.plugin.Invocation;
+import org.apache.ibatis.plugin.Signature;
+import org.apache.ibatis.reflection.MetaObject;
+import org.apache.ibatis.session.Configuration;
+import org.apache.ibatis.session.ResultHandler;
+import org.apache.ibatis.type.TypeHandlerRegistry;
+import org.dromara.common.mybatis.config.properties.SqlLogProperties;
+
+import java.lang.reflect.InvocationTargetException;
+import java.sql.Statement;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.temporal.TemporalAccessor;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * 完整 SQL 日志拦截器。
+ *
+ * @author Lion Li
+ */
+@Slf4j(topic = "SQL_FULL")
+@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}),
+ @Signature(type = StatementHandler.class, method = "queryCursor", args = {Statement.class})
+})
+public class SqlLogInterceptor implements Interceptor {
+
+ /**
+ * 单条日志分片长度。
+ */
+ private static final int CHUNK_SIZE = 8000;
+
+ /**
+ * SQL 空白字符匹配。
+ */
+ private static final String BLANK_REGEX = "\\s+";
+
+ /**
+ * 日期时间格式。
+ */
+ private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+
+ /**
+ * 日期格式。
+ */
+ private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+
+ /**
+ * 时间格式。
+ */
+ private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm:ss");
+
+ /**
+ * 控制台输出锁,避免多线程 SQL 日志互相穿插。
+ */
+ private static final ReentrantLock CONSOLE_LOCK = new ReentrantLock();
+
+ /**
+ * SQL 日志配置。
+ */
+ private final SqlLogProperties sqlLogProperties;
+
+ public SqlLogInterceptor(SqlLogProperties sqlLogProperties) {
+ this.sqlLogProperties = sqlLogProperties;
+ }
+
+ @Override
+ public Object intercept(Invocation invocation) throws Throwable {
+ StatementHandler statementHandler = PluginUtils.realTarget(invocation.getTarget());
+ BoundSql boundSql = statementHandler.getBoundSql();
+ MappedStatement mappedStatement = PluginUtils.mpStatementHandler(statementHandler).mappedStatement();
+ long startTime = System.currentTimeMillis();
+ try {
+ Object result = invocation.proceed();
+ printSql(mappedStatement, boundSql, System.currentTimeMillis() - startTime, null);
+ return result;
+ } catch (Throwable e) {
+ printSql(mappedStatement, boundSql, System.currentTimeMillis() - startTime, e);
+ throw e;
+ }
+ }
+
+ /**
+ * 输出 SQL。
+ *
+ * @param mappedStatement 映射语句
+ * @param boundSql 绑定 SQL
+ * @param elapsedTime 执行耗时
+ * @param throwable 执行异常
+ */
+ private void printSql(MappedStatement mappedStatement, BoundSql boundSql, long elapsedTime, Throwable throwable) {
+ String fullSql = buildFullSql(mappedStatement.getConfiguration(), boundSql);
+ String message = buildLogMessage(mappedStatement, elapsedTime, fullSql, throwable);
+ printChunk(message);
+ }
+
+ /**
+ * 构建日志内容。
+ *
+ * @param mappedStatement 映射语句
+ * @param elapsedTime 执行耗时
+ * @param fullSql 完整 SQL
+ * @param throwable 执行异常
+ * @return 日志内容
+ */
+ private String buildLogMessage(MappedStatement mappedStatement, long elapsedTime, String fullSql, Throwable throwable) {
+ if (isLogOutput()) {
+ String message = StrUtil.format("Consume Time:{} ms {} Mapper ID:{} Execute SQL:{}",
+ elapsedTime, DateUtil.now(), mappedStatement.getId(), fullSql);
+ String errorMessage = formatThrowable(throwable);
+ if (StrUtil.isNotBlank(errorMessage)) {
+ message = message + " Execute Error:" + errorMessage;
+ }
+ return message;
+ }
+ String message = StrUtil.format("Consume Time:{} ms {}\nMapper ID:{}\nExecute SQL:{}",
+ elapsedTime, DateUtil.now(), mappedStatement.getId(), fullSql);
+ String errorMessage = formatThrowable(throwable);
+ if (StrUtil.isNotBlank(errorMessage)) {
+ message = message + "\nExecute Error:" + errorMessage;
+ }
+ return message;
+ }
+
+ /**
+ * 格式化执行异常。
+ *
+ * @param throwable 执行异常
+ * @return 异常信息
+ */
+ private String formatThrowable(Throwable throwable) {
+ if (throwable == null) {
+ return StrUtil.EMPTY;
+ }
+ Throwable realThrowable = unwrapThrowable(throwable);
+ String message = realThrowable.getMessage();
+ if (StrUtil.isBlank(message)) {
+ return StrUtil.EMPTY;
+ }
+ return realThrowable.getClass().getName() + ": " + message;
+ }
+
+ /**
+ * 解包反射调用异常。
+ *
+ * @param throwable 执行异常
+ * @return 实际异常
+ */
+ private Throwable unwrapThrowable(Throwable throwable) {
+ if (throwable instanceof InvocationTargetException invocationTargetException
+ && invocationTargetException.getTargetException() != null) {
+ return invocationTargetException.getTargetException();
+ }
+ return throwable;
+ }
+
+ /**
+ * 构建完整 SQL。
+ *
+ * @param configuration MyBatis 配置
+ * @param boundSql 绑定 SQL
+ * @return 完整 SQL
+ */
+ private String buildFullSql(Configuration configuration, BoundSql boundSql) {
+ String sql = boundSql.getSql().replaceAll(BLANK_REGEX, " ").trim();
+ List parameters = buildParameterValues(configuration, boundSql);
+ return replacePlaceholders(sql, parameters);
+ }
+
+ /**
+ * 构建参数值集合。
+ *
+ * @param configuration MyBatis 配置
+ * @param boundSql 绑定 SQL
+ * @return 参数值集合
+ */
+ private List buildParameterValues(Configuration configuration, BoundSql boundSql) {
+ List parameterMappings = boundSql.getParameterMappings();
+ List parameters = new ArrayList<>(parameterMappings.size());
+ Object parameterObject = boundSql.getParameterObject();
+ TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
+ MetaObject metaObject = parameterObject == null ? null : configuration.newMetaObject(parameterObject);
+ for (ParameterMapping parameterMapping : parameterMappings) {
+ if (parameterMapping.getMode() == ParameterMode.OUT) {
+ continue;
+ }
+ String propertyName = parameterMapping.getProperty();
+ Object value;
+ if (boundSql.hasAdditionalParameter(propertyName)) {
+ value = boundSql.getAdditionalParameter(propertyName);
+ } else if (parameterObject == null) {
+ value = null;
+ } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
+ value = parameterObject;
+ } else if (metaObject != null && metaObject.hasGetter(propertyName)) {
+ value = metaObject.getValue(propertyName);
+ } else {
+ value = null;
+ }
+ parameters.add(formatParameter(value));
+ }
+ return parameters;
+ }
+
+ /**
+ * 替换 SQL 占位符。
+ *
+ * @param sql SQL 模板
+ * @param parameters 参数集合
+ * @return 完整 SQL
+ */
+ private String replacePlaceholders(String sql, List parameters) {
+ if (parameters.isEmpty()) {
+ return sql;
+ }
+ StringBuilder builder = new StringBuilder(sql.length() + parameters.size() * 8);
+ int parameterIndex = 0;
+ boolean inSingleQuote = false;
+ boolean inDoubleQuote = false;
+ for (int i = 0; i < sql.length(); i++) {
+ char current = sql.charAt(i);
+ if (current == '\'' && !inDoubleQuote) {
+ inSingleQuote = !inSingleQuote;
+ } else if (current == '"' && !inSingleQuote) {
+ inDoubleQuote = !inDoubleQuote;
+ }
+ if (current == '?' && !inSingleQuote && !inDoubleQuote && parameterIndex < parameters.size()) {
+ builder.append(parameters.get(parameterIndex++));
+ } else {
+ builder.append(current);
+ }
+ }
+ return builder.toString();
+ }
+
+ /**
+ * 格式化参数值。
+ *
+ * @param value 参数值
+ * @return SQL 参数文本
+ */
+ private String formatParameter(Object value) {
+ if (value == null) {
+ return "null";
+ }
+ if (value instanceof Number || value instanceof Boolean) {
+ return value.toString();
+ }
+ if (value instanceof Date date) {
+ return quote(DateUtil.formatDateTime(date));
+ }
+ if (value instanceof LocalDateTime localDateTime) {
+ return quote(localDateTime.format(DATE_TIME_FORMATTER));
+ }
+ if (value instanceof LocalDate localDate) {
+ return quote(localDate.format(DATE_FORMATTER));
+ }
+ if (value instanceof LocalTime localTime) {
+ return quote(localTime.format(TIME_FORMATTER));
+ }
+ if (value instanceof TemporalAccessor) {
+ return quote(value.toString());
+ }
+ if (value instanceof Enum> enumValue) {
+ return quote(enumValue.name());
+ }
+ return quote(value.toString());
+ }
+
+ /**
+ * 包装字符串参数。
+ *
+ * @param value 字符串值
+ * @return SQL 字符串参数
+ */
+ private String quote(String value) {
+ return "'" + value.replace("'", "''") + "'";
+ }
+
+ /**
+ * 分片输出日志,避免日志链路截断超长 SQL。
+ *
+ * @param message 日志内容
+ */
+ private void printChunk(String message) {
+ if (!isLogOutput()) {
+ printConsole(message);
+ return;
+ }
+ if (message.length() <= CHUNK_SIZE) {
+ print(message);
+ return;
+ }
+ String sqlLogId = UUID.randomUUID().toString();
+ int total = (message.length() + CHUNK_SIZE - 1) / CHUNK_SIZE;
+ for (int i = 0; i < total; i++) {
+ int start = i * CHUNK_SIZE;
+ int end = Math.min(start + CHUNK_SIZE, message.length());
+ print(StrUtil.format("sqlLogId={} part={}/{} {}", sqlLogId, i + 1, total, message.substring(start, end)));
+ }
+ }
+
+ /**
+ * 输出 SQL 日志。
+ *
+ * @param message 日志内容
+ */
+ private void print(String message) {
+ if (isLogOutput()) {
+ log.info(message);
+ return;
+ }
+ printConsole(message);
+ }
+
+ /**
+ * 输出控制台日志。
+ *
+ * @param message 日志内容
+ */
+ private void printConsole(String message) {
+ CONSOLE_LOCK.lock();
+ try {
+ System.err.println(message);
+ System.err.println();
+ } finally {
+ CONSOLE_LOCK.unlock();
+ }
+ }
+
+ /**
+ * 是否使用日志系统输出。
+ *
+ * @return true 使用日志系统输出,false 使用控制台输出
+ */
+ private boolean isLogOutput() {
+ return StrUtil.equalsIgnoreCase("log", sqlLogProperties.getOutput());
+ }
+
+}
diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/resources/common-mybatis.yml b/ruoyi-common/ruoyi-common-mybatis/src/main/resources/common-mybatis.yml
index 14662e16a..247f4a80a 100644
--- a/ruoyi-common/ruoyi-common-mybatis/src/main/resources/common-mybatis.yml
+++ b/ruoyi-common/ruoyi-common-mybatis/src/main/resources/common-mybatis.yml
@@ -13,9 +13,7 @@ mybatis-plus:
# MyBatis 自动映射时未知列或未知属性处理策
# NONE:不做处理 WARNING:打印相关警告 FAILING:抛出异常和详细信息
autoMappingUnknownColumnBehavior: NONE
- # 更详细的日志输出 会有性能损耗 org.apache.ibatis.logging.stdout.StdOutImpl
- # 关闭日志记录 (可单纯使用 p6spy 分析) org.apache.ibatis.logging.nologging.NoLoggingImpl
- # 默认日志输出 org.apache.ibatis.logging.slf4j.Slf4jImpl
+ # 关闭默认日志输出 org.apache.ibatis.logging.nologging.NoLoggingImpl
logImpl: org.apache.ibatis.logging.nologging.NoLoggingImpl
global-config:
# 是否打印 Logo banner
diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/resources/spy.properties b/ruoyi-common/ruoyi-common-mybatis/src/main/resources/spy.properties
deleted file mode 100644
index f3ed7d8eb..000000000
--- a/ruoyi-common/ruoyi-common-mybatis/src/main/resources/spy.properties
+++ /dev/null
@@ -1,20 +0,0 @@
-# p6spy 性能分析插件配置文件
-modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
-# 自定义日志打印
-logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
-#日志输出到控制台
-appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
-# 使用日志系统记录 sql
-#appender=com.p6spy.engine.spy.appender.Slf4JLogger
-# 取消JDBC URL前缀
-useprefix=true
-# 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset.
-excludecategories=info,debug,result,commit,resultset
-# 日期格式
-dateformat=yyyy-MM-dd HH:mm:ss
-# SQL语句打印时间格式
-databaseDialectTimestampFormat=yyyy-MM-dd HH:mm:ss
-# 是否过滤 Log
-filter=true
-# 过滤 Log 时所排除的 sql 关键字,以逗号分隔
-exclude=