From 42e7196b137411899743919b0cd2c809785868f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=96=AF=E7=8B=82=E7=9A=84=E7=8B=AE=E5=AD=90Li?= <15040126243@163.com> Date: Mon, 26 Oct 2026 18:38:20 +0800 Subject: [PATCH] =?UTF-8?q?update=20=E4=BC=98=E5=8C=96=20sql=E8=BE=93?= =?UTF-8?q?=E5=87=BA=E6=8B=A6=E6=88=AA=E5=99=A8=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E6=A0=B9=E6=8D=AE=E8=A1=A8=E5=90=8D=E5=BF=BD=E7=95=A5sql?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/application-dev.yml | 2 + .../src/main/resources/application-prod.yml | 2 + .../config/properties/SqlLogProperties.java | 8 ++ .../interceptor/SqlLogInterceptor.java | 28 +++++++ .../interceptor/SqlLogInterceptorTest.java | 84 +++++++++++++++++++ 5 files changed, 124 insertions(+) create mode 100644 ruoyi-common/ruoyi-common-mybatis/src/test/java/org/dromara/common/mybatis/interceptor/SqlLogInterceptorTest.java diff --git a/ruoyi-admin/src/main/resources/application-dev.yml b/ruoyi-admin/src/main/resources/application-dev.yml index ae9b6ff9e..9b5dd8628 100644 --- a/ruoyi-admin/src/main/resources/application-dev.yml +++ b/ruoyi-admin/src/main/resources/application-dev.yml @@ -82,6 +82,8 @@ mybatis-plus: enabled: true # 输出方式,可选 console、log output: console + # 忽略高频轮询表的成功 SQL 日志;执行异常仍会输出 + ignore-tables: [flow_event_wait] --- # 数据源配置 spring: diff --git a/ruoyi-admin/src/main/resources/application-prod.yml b/ruoyi-admin/src/main/resources/application-prod.yml index e581b182c..41c587d68 100644 --- a/ruoyi-admin/src/main/resources/application-prod.yml +++ b/ruoyi-admin/src/main/resources/application-prod.yml @@ -85,6 +85,8 @@ mybatis-plus: enabled: false # 输出方式,可选 console、log output: console + # 忽略高频轮询表的成功 SQL 日志;执行异常仍会输出 + ignore-tables: [ flow_event_wait ] --- # 数据源配置 spring: 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 index fe07f0105..a30fc5b07 100644 --- 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 @@ -3,6 +3,9 @@ package org.dromara.common.mybatis.config.properties; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; +import java.util.ArrayList; +import java.util.List; + /** * SQL 日志配置。 * @@ -22,4 +25,9 @@ public class SqlLogProperties { */ private String output = "console"; + /** + * 不输出成功执行日志的表名;执行异常仍会输出。 + */ + private List ignoreTables = new ArrayList<>(); + } 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 index d17ab7810..388b8a39b 100644 --- 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 @@ -30,6 +30,7 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.UUID; +import java.util.regex.Pattern; /** * 完整 SQL 日志拦截器。 @@ -55,6 +56,8 @@ public class SqlLogInterceptor implements Interceptor { */ private static final String BLANK_REGEX = "\\s+"; + private static final Pattern SQL_STRING_LITERAL = Pattern.compile("'(?:''|[^'])*'"); + /** * 日期时间格式。 */ @@ -75,8 +78,17 @@ public class SqlLogInterceptor implements Interceptor { */ private final SqlLogProperties sqlLogProperties; + private final List ignoredTablePatterns; + public SqlLogInterceptor(SqlLogProperties sqlLogProperties) { this.sqlLogProperties = sqlLogProperties; + this.ignoredTablePatterns = sqlLogProperties.getIgnoreTables().stream() + .filter(StrUtil::isNotBlank) + .map(String::trim) + .map(table -> Pattern.compile("(?i)\\b(?:FROM|JOIN|UPDATE|INTO)\\s+" + + "(?:[`\"\\[]?[A-Za-z_][A-Za-z0-9_]*[`\"\\]]?\\s*\\.\\s*)?" + + "[`\"\\[]?" + Pattern.quote(table) + "[`\"\\]]?(?=\\s|[,);]|$)")) + .toList(); } @Override @@ -104,11 +116,27 @@ public class SqlLogInterceptor implements Interceptor { * @param throwable 执行异常 */ private void printSql(MappedStatement mappedStatement, BoundSql boundSql, long elapsedTime, Throwable throwable) { + if (throwable == null && isIgnoredTableSql(boundSql.getSql())) { + return; + } String fullSql = buildFullSql(mappedStatement.getConfiguration(), boundSql); String message = buildLogMessage(mappedStatement, elapsedTime, fullSql, throwable); printChunk(message); } + boolean isIgnoredTableSql(String sql) { + if (ignoredTablePatterns.isEmpty()) { + return false; + } + String statement = sql.indexOf('\'') >= 0 ? SQL_STRING_LITERAL.matcher(sql).replaceAll("''") : sql; + for (Pattern pattern : ignoredTablePatterns) { + if (pattern.matcher(statement).find()) { + return true; + } + } + return false; + } + /** * 构建日志内容。 * diff --git a/ruoyi-common/ruoyi-common-mybatis/src/test/java/org/dromara/common/mybatis/interceptor/SqlLogInterceptorTest.java b/ruoyi-common/ruoyi-common-mybatis/src/test/java/org/dromara/common/mybatis/interceptor/SqlLogInterceptorTest.java new file mode 100644 index 000000000..fb906a695 --- /dev/null +++ b/ruoyi-common/ruoyi-common-mybatis/src/test/java/org/dromara/common/mybatis/interceptor/SqlLogInterceptorTest.java @@ -0,0 +1,84 @@ +package org.dromara.common.mybatis.interceptor; + +import com.baomidou.mybatisplus.core.MybatisConfiguration; +import com.baomidou.mybatisplus.core.MybatisSqlSessionFactoryBuilder; +import org.apache.ibatis.annotations.Select; +import org.apache.ibatis.datasource.unpooled.UnpooledDataSource; +import org.apache.ibatis.mapping.Environment; +import org.apache.ibatis.session.SqlSession; +import org.apache.ibatis.session.SqlSessionFactory; +import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory; +import org.dromara.common.mybatis.config.properties.SqlLogProperties; +import org.junit.jupiter.api.Test; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.nio.charset.StandardCharsets; +import java.sql.Connection; +import java.sql.Statement; +import java.util.List; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class SqlLogInterceptorTest { + + @Test + void ignoredTableStillExecutesAndOtherTableStillLogs() throws Exception { + SqlLogProperties properties = new SqlLogProperties(); + properties.setIgnoreTables(List.of("flow_event_wait")); + SqlLogInterceptor interceptor = new SqlLogInterceptor(properties); + String url = "jdbc:h2:mem:sql_log_" + UUID.randomUUID().toString().replace("-", "") + ";DB_CLOSE_DELAY=-1"; + UnpooledDataSource dataSource = new UnpooledDataSource("org.h2.Driver", url, "sa", ""); + try (Connection connection = dataSource.getConnection(); Statement statement = connection.createStatement()) { + statement.execute("CREATE TABLE flow_event_wait (id BIGINT PRIMARY KEY)"); + statement.execute("CREATE TABLE audit_record (id BIGINT PRIMARY KEY)"); + statement.execute("INSERT INTO flow_event_wait VALUES (1)"); + statement.execute("INSERT INTO audit_record VALUES (2)"); + } + + MybatisConfiguration configuration = new MybatisConfiguration(); + configuration.setEnvironment(new Environment("h2", new JdbcTransactionFactory(), dataSource)); + configuration.addInterceptor(interceptor); + configuration.addMapper(LogMapper.class); + SqlSessionFactory factory = new MybatisSqlSessionFactoryBuilder().build(configuration); + PrintStream originalErr = System.err; + ByteArrayOutputStream output = new ByteArrayOutputStream(); + try (PrintStream capture = new PrintStream(output, true, StandardCharsets.UTF_8)) { + System.setErr(capture); + try (SqlSession session = factory.openSession()) { + assertEquals(1L, session.getMapper(LogMapper.class).eventWaitId()); + assertEquals(2L, session.getMapper(LogMapper.class).auditId()); + } + } finally { + System.setErr(originalErr); + } + String logs = output.toString(StandardCharsets.UTF_8); + assertFalse(logs.contains("flow_event_wait")); + assertTrue(logs.contains("audit_record")); + } + + @Test + void matchesTableReferencesWithoutMatchingLiteralsOrSimilarNames() { + SqlLogProperties properties = new SqlLogProperties(); + properties.setIgnoreTables(List.of("flow_event_wait")); + SqlLogInterceptor interceptor = new SqlLogInterceptor(properties); + + assertTrue(interceptor.isIgnoredTableSql("select * from flow_event_wait where id = ?")); + assertTrue(interceptor.isIgnoredTableSql("select * from `app`.`flow_event_wait`")); + assertTrue(interceptor.isIgnoredTableSql("select * from audit_record join FLOW_EVENT_WAIT w on w.id = audit_record.id")); + assertTrue(interceptor.isIgnoredTableSql("update flow_event_wait set status = ?")); + assertFalse(interceptor.isIgnoredTableSql("select 'from flow_event_wait' from audit_record")); + assertFalse(interceptor.isIgnoredTableSql("select * from flow_event_wait_history")); + } + + interface LogMapper { + @Select("SELECT id FROM flow_event_wait") + Long eventWaitId(); + + @Select("SELECT id FROM audit_record") + Long auditId(); + } +}