@Slf4j将日志记录到磁盘和数据库

文章目录

1、背景介绍

现在我一个SpringBoot项目想记录日志,大概可以分为下面这几种:

  1. 用户操作日志:作用是记录什么用户在什么时间点访问了什么接口做了什么操作,相当于对用户在系统中的一举一动做了一个监控;
  2. 登录登出日志:就是将所有用户登录系统和登出系统记录到数据库,比如时间、IP、IP归属地等做一个记录,这个简单,就不过多赘述了
  3. 开发调试日志:就是我们常用的log.info("xxxxx");记录一些日志信息到磁盘中,方便上生产后,出现Bug时,可以多一些日志信息帮助我们尽快定位问题的

今天我们主要来好好聊一下开发调试日志

2、存本地

我们先来介绍一下,开发调试日志如何存本地磁盘

2.1、配置文件

首先我们需要在SpringBoot工程的resources下新建一个名叫【logback-spring.xml】的文件,内容如下:

xml 复制代码
<!-- 级别从高到低 OFF 、 FATAL 、 ERROR 、 WARN 、 INFO 、 DEBUG 、 TRACE 、 ALL -->
<!-- 日志输出规则 根据当前ROOT 级别,日志输出时,级别高于root默认的级别时 会输出 -->
<!-- 以下 每个配置的 filter 是过滤掉输出文件里面,会出现高级别文件,依然出现低级别的日志信息,通过filter 过滤只记录本级别的日志 -->
<!-- scan 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。 -->
<!-- scanPeriod 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
<!-- debug 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
<configuration scan="true" scanPeriod="60 seconds" debug="false">
    <!-- 动态日志级别 -->
    <jmxConfigurator />
    <property name="charset" value="UTF-8"/>
    <!-- 定义日志文件 输出位置 -->
    <property name="log_dir" value="C:/LOGS/EasyJavaSE" />
    <!-- 日志最大的历史 30天 -->
    <property name="maxHistory" value="30" />
    <!-- 单个日志文件的最大大小 -->
    <property name="maxFileSize" value="5MB" />
    <!--格式化输出:%d表示日期,%t:表示线程名,%-5level:级别从左显示5个字符宽度,%c:类全路径,%msg:日志消息,%M:方法名,%L:日志所属行号,%n:换行符(Windows平台为"\r\n",Unix平台为"\n") -->
    <property name="FORMAT" value="[%X{TRACE_ID}] - %-5level %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %c.%M:%L:%msg%n"/>

    <!-- ConsoleAppender 控制台输出日志 -->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>
                <!-- 设置日志输出格式 -->
                ${FORMAT}
            </pattern>
        </encoder>
    </appender>

    <!-- ERROR级别日志 -->
    <!-- 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 RollingFileAppender -->
    <appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录WARN级别的日志 -->
        <!-- 果日志级别等于配置级别,过滤器会根据onMath 和 onMismatch接收或拒绝日志。 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <!-- 设置过滤级别 -->
            <level>ERROR</level>
            <!-- 用于配置符合过滤条件的操作 -->
            <onMatch>ACCEPT</onMatch>
            <!-- 用于配置不符合过滤条件的操作 -->
            <onMismatch>DENY</onMismatch>
        </filter>
        <!-- 最常用的滚动策略,它根据时间来制定滚动策略.既负责滚动也负责出发滚动 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--
            滚动时产生的文件的存放位置及文件名称 %d{yyyy-MM-dd}:按天进行日志滚动
            %i:当文件大小超过maxFileSize时,按照i进行文件滚动,i的值从0开始递增
            -->
            <fileNamePattern>
                ${log_dir}/error/%d{yyyy-MM-dd}/error-%i.log
            </fileNamePattern>
            <!-- 可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件假设设置每个月滚动,且<maxHistory>是6, 则只保存最近6个月的文件,删除之前的旧文件。注意,删除旧文件是,那些为了归档而创建的目录也会被删除 -->
            <maxHistory>${maxHistory}</maxHistory>
            <!-- 日志文件的最大大小 -->
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>${maxFileSize}</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <encoder>
            <pattern>
                <!-- 设置日志输出格式 -->
                ${FORMAT}
            </pattern>
        </encoder>
    </appender>

    <!-- WARN级别日志 appender -->
    <appender name="WARN" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录WARN级别的日志 -->
        <!-- 果日志级别等于配置级别,过滤器会根据onMath 和 onMismatch接收或拒绝日志。 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <!-- 设置过滤级别 -->
            <level>WARN</level>
            <!-- 用于配置符合过滤条件的操作 -->
            <onMatch>ACCEPT</onMatch>
            <!-- 用于配置不符合过滤条件的操作 -->
            <onMismatch>DENY</onMismatch>
        </filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log_dir}/warn/%d{yyyy-MM-dd}/warn-%i.log</fileNamePattern>
            <maxHistory>${maxHistory}</maxHistory>
            <!-- 日志文件的最大大小 -->
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>${maxFileSize}</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <encoder>
            <pattern>${FORMAT}</pattern>
        </encoder>
    </appender>

    <!-- INFO级别日志 appender -->
    <appender name="INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log_dir}/info/%d{yyyy-MM-dd}/info-%i.log</fileNamePattern>
            <maxHistory>${maxHistory}</maxHistory>
            <!-- 日志文件的最大大小 -->
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>${maxFileSize}</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <encoder>
            <pattern>${FORMAT}</pattern>
        </encoder>
    </appender>

    <!-- DEBUG级别日志 appender -->
    <appender name="DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>DEBUG</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log_dir}/debug/%d{yyyy-MM-dd}/debug-%i.log</fileNamePattern>
            <maxHistory>${maxHistory}</maxHistory>
            <!-- 日志文件的最大大小 -->
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>${maxFileSize}</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <encoder>
            <pattern>${FORMAT}</pattern>
        </encoder>
    </appender>

    <!-- root级别 -->
    <root>
        <!-- 只有该级别日志及以上级别日志才会输出到指定渠道 -->
        <!-- 测试:debug。上生产环境时,需要改成info或error -->
        <level value="info" />
        <!-- 控制台输出渠道 -->
        <appender-ref ref="console" />
        <!-- 文件输出渠道 -->
        <appender-ref ref="ERROR" />
        <appender-ref ref="INFO" />
        <appender-ref ref="WARN" />
        <appender-ref ref="DEBUG" />
    </root>
</configuration>

2.2、使用

要想要使用也非常简单,只需要先在pom.xml中导入下面依赖:

xml 复制代码
<!--lombok-->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>

然后在需要记录日志的类上打一个下面的注解:

java 复制代码
@Slf4j
public class TestController{
    //........
}

然后就可以直接使用了,像这样:

java 复制代码
@Slf4j
@RestController
@RequestMapping("/test")
public class TestController{
    
    @GetMapping("/test002/{name}")
    public JSONResult test002(@PathVariable("name") String name){
        log.info("这是 info 级别日志");
        log.warn("这是 warn 级别日志");
        log.error("这是 error 级别日志");
        log.debug("这是 debug 级别日志");
        return JSONResult.success(name);
    }
}

项目启动,浏览器访问:http😕/localhost:8008/test/test002/tom,然后你去看磁盘对应目录中,就会记录日志成功了

3、存数据库

上面方式虽然可以记录开发调试日志到磁盘,但是有个问题是,每次要看日志的时候,都需要连接生产环境的Linux服务器,然后拉取日志文件到本地了再分析,这样比较耗时,所以我们可以优化一下,将这些日志信息存到数据库中,然后搞一个管理页面直接展示,这样查看生产环境日志就简单多了,改造步骤如下:

3.1、配置文件改造

【logback-spring.xml】配置文件改成下面这样:

xml 复制代码
<!-- 级别从高到低 OFF 、 FATAL 、 ERROR 、 WARN 、 INFO 、 DEBUG 、 TRACE 、 ALL -->
<!-- 日志输出规则 根据当前ROOT 级别,日志输出时,级别高于root默认的级别时 会输出 -->
<!-- 以下 每个配置的 filter 是过滤掉输出文件里面,会出现高级别文件,依然出现低级别的日志信息,通过filter 过滤只记录本级别的日志 -->
<!-- scan 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。 -->
<!-- scanPeriod 设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
<!-- debug 当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
<configuration scan="true" scanPeriod="60 seconds" debug="false">
    <!-- 动态日志级别 -->
    <jmxConfigurator />
    <property name="charset" value="UTF-8"/>
    <!-- 定义日志文件 输出位置 -->
    <property name="log_dir" value="C:/LOGS/EasyJavaSE" />
    <!-- 日志最大的历史 30天 -->
    <property name="maxHistory" value="30" />
    <!-- 单个日志文件的最大大小 -->
    <property name="maxFileSize" value="5MB" />
    <!--格式化输出:%d表示日期,%t:表示线程名,%-5level:级别从左显示5个字符宽度,%c:类全路径,%msg:日志消息,%M:方法名,%L:日志所属行号,%n:换行符(Windows平台为"\r\n",Unix平台为"\n") -->
    <property name="FORMAT" value="[%X{TRACE_ID}] - %-5level %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %c.%M:%L:%msg%n"/>

    <!-- ConsoleAppender 控制台输出日志 -->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>
                <!-- 设置日志输出格式 -->
                ${FORMAT}
            </pattern>
        </encoder>
    </appender>

    <!-- ERROR级别日志 -->
    <!-- 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 RollingFileAppender -->
    <appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录WARN级别的日志 -->
        <!-- 果日志级别等于配置级别,过滤器会根据onMath 和 onMismatch接收或拒绝日志。 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <!-- 设置过滤级别 -->
            <level>ERROR</level>
            <!-- 用于配置符合过滤条件的操作 -->
            <onMatch>ACCEPT</onMatch>
            <!-- 用于配置不符合过滤条件的操作 -->
            <onMismatch>DENY</onMismatch>
        </filter>
        <!-- 最常用的滚动策略,它根据时间来制定滚动策略.既负责滚动也负责出发滚动 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--
            滚动时产生的文件的存放位置及文件名称 %d{yyyy-MM-dd}:按天进行日志滚动
            %i:当文件大小超过maxFileSize时,按照i进行文件滚动,i的值从0开始递增
            -->
            <fileNamePattern>
                ${log_dir}/error/%d{yyyy-MM-dd}/error-%i.log
            </fileNamePattern>
            <!-- 可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件假设设置每个月滚动,且<maxHistory>是6, 则只保存最近6个月的文件,删除之前的旧文件。注意,删除旧文件是,那些为了归档而创建的目录也会被删除 -->
            <maxHistory>${maxHistory}</maxHistory>
            <!-- 日志文件的最大大小 -->
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>${maxFileSize}</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <encoder>
            <pattern>
                <!-- 设置日志输出格式 -->
                ${FORMAT}
            </pattern>
        </encoder>
    </appender>

    <!-- WARN级别日志 appender -->
    <appender name="WARN" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 过滤器,只记录WARN级别的日志 -->
        <!-- 果日志级别等于配置级别,过滤器会根据onMath 和 onMismatch接收或拒绝日志。 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <!-- 设置过滤级别 -->
            <level>WARN</level>
            <!-- 用于配置符合过滤条件的操作 -->
            <onMatch>ACCEPT</onMatch>
            <!-- 用于配置不符合过滤条件的操作 -->
            <onMismatch>DENY</onMismatch>
        </filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log_dir}/warn/%d{yyyy-MM-dd}/warn-%i.log</fileNamePattern>
            <maxHistory>${maxHistory}</maxHistory>
            <!-- 日志文件的最大大小 -->
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>${maxFileSize}</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <encoder>
            <pattern>${FORMAT}</pattern>
        </encoder>
    </appender>

    <!-- INFO级别日志 appender -->
    <appender name="INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log_dir}/info/%d{yyyy-MM-dd}/info-%i.log</fileNamePattern>
            <maxHistory>${maxHistory}</maxHistory>
            <!-- 日志文件的最大大小 -->
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>${maxFileSize}</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <encoder>
            <pattern>${FORMAT}</pattern>
        </encoder>
    </appender>

    <!-- DEBUG级别日志 appender -->
    <appender name="DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>DEBUG</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log_dir}/debug/%d{yyyy-MM-dd}/debug-%i.log</fileNamePattern>
            <maxHistory>${maxHistory}</maxHistory>
            <!-- 日志文件的最大大小 -->
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>${maxFileSize}</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <encoder>
            <pattern>${FORMAT}</pattern>
        </encoder>
    </appender>

    <!-- 将日志写入数据库 -->
    <appender name="DB" class="ch.qos.logback.classic.db.DBAppender">
        <connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource">
            <driverClass>com.mysql.cj.jdbc.Driver</driverClass>
            <url>jdbc:mysql://127.0.0.1:3306/easyjavase?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=UTC</url>
            <user>root</user>
            <password>123456</password>
        </connectionSource>

        <!--自定义过滤器-->
        <filter class="cn.wujiangbo.filter.LogFilter">
        </filter>
    </appender>

    <!-- root级别 -->
    <root>
        <!-- 只有该级别日志及以上级别日志才会输出到指定渠道 -->
        <!-- 测试:debug。上生产环境时,需要改成info或error -->
        <level value="info" />
        <!-- 控制台输出渠道 -->
        <appender-ref ref="console" />
        <!-- 文件输出渠道 -->
        <appender-ref ref="ERROR" />
        <appender-ref ref="INFO" />
        <appender-ref ref="WARN" />
        <appender-ref ref="DEBUG" />
        <appender-ref ref="DB" />
    </root>
</configuration>

3.2、过滤器编写

新建一个过滤器,处理日志,哪些需要入库,哪些不需要入库,都在这个过滤器中指定,代码如下:

java 复制代码
package cn.wujiangbo.filter;

import ch.qos.logback.classic.spi.LoggingEvent;
import ch.qos.logback.core.filter.Filter;
import ch.qos.logback.core.spi.FilterReply;
import cn.hutool.extra.spring.SpringUtil;
import cn.wujiangbo.domain.system.EasySlf4jLogging;
import cn.wujiangbo.service.system.EasySlf4jLoggingService;
import cn.wujiangbo.utils.DateUtils;

/**
 * <p>Slf4j日志入库-过滤器</p>
 *
 * @author 波波老师(微信:javabobo0513)
 */
public class LogFilter extends Filter<LoggingEvent> {

    public EasySlf4jLoggingService easySlf4jLoggingService = null;

    @Override
    public FilterReply decide(LoggingEvent event) {
        String loggerName = event.getLoggerName();
        if(loggerName.startsWith("cn.wujiangbo")){
            //项目本身的日志才会入库
            EasySlf4jLogging log = new EasySlf4jLogging();
            log.setLogTime(DateUtils.getCurrentLocalDateTime());
            log.setLogThread(event.getThreadName());
            log.setLogClass(loggerName);
            log.setLogLevel(event.getLevel().levelStr);
            log.setTrackId(event.getMDCPropertyMap().get("TRACE_ID"));
            log.setLogContent(event.getFormattedMessage());//日志内容

            easySlf4jLoggingService = SpringUtil.getBean(EasySlf4jLoggingService.class);
            //日志入库
            easySlf4jLoggingService.asyncSave(log);
            return FilterReply.ACCEPT;
        }else{
            //非项目本身的日志不会入库
            return FilterReply.DENY;
        }
    }
}

3.3、表准备

数据库准备一张表存开发日志信息,建表语句如下:

sql 复制代码
DROP TABLE IF EXISTS `easy_slf4j_logging`;
CREATE TABLE `easy_slf4j_logging`  (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `log_level` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '日志级别',
  `log_content` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '日志内容',
  `log_time` datetime NULL DEFAULT NULL COMMENT '日志时间',
  `log_class` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '日志类路径',
  `log_thread` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '日志线程',
  `track_id` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '全局跟踪ID',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = 'Slf4j日志表' ROW_FORMAT = Compact;

3.4、添加依赖

pom.xml中需要添加下面依赖:

xml 复制代码
<!--slf4j日志写入数据库的依赖-->
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-core</artifactId>
    <version>1.2.7</version>
</dependency>

3.5、测试

启动项目,浏览器访问:http://localhost:8008/test/test002/tom,然后表中就有数据了,如下:

管理页面就可以直接查到了,如下:

nice

4、优化

4.1、日志定期删除

系统中会有各种各样的日志,防止数据过大,我们可以只保留最近6个月的数据,6个月以前的日志信息将其删除掉,可以搞一个定时任务,每天晚上11:30执行一次,当然,什么时候执行,大家根据自己实际情况修改,我这里定时任务代码如下:

java 复制代码
package cn.wujiangbo.task;

import cn.wujiangbo.mapper.system.EasySlf4jLoggingMapper;
import cn.wujiangbo.utils.DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;

/**
 * <p>定时任务类</p>
 *
 * @author 波波老师(微信 : javabobo0513)
 */
@Component
@Slf4j
public class CommonTask {

    @Resource
    public EasySlf4jLoggingMapper easySlf4jLoggingMapper;

    /**
     * 删除日志表数据
     */
    @Scheduled(cron = "0 30 23 ? * *")//每天晚上11:30触发
    public void task001() {
        log.info("--------【定时任务:删除数据库日志-每晚11:30触发一次】-------------执行开始,时间:{}", DateUtils.getCurrentDateString());
        easySlf4jLoggingMapper.deleteLog();
        log.info("--------【定时任务:删除数据库日志-每晚11:30触发一次】-------------执行结束,时间:{}", DateUtils.getCurrentDateString());
    }
}

SQL语句如下:

sql 复制代码
delete from easy_slf4j_logging where log_time <= DATE_SUB(CURDATE(), INTERVAL 6 MONTH)
相关推荐
用户83071968408219 小时前
Spring Boot 集成 RabbitMQ :8 个最佳实践,杜绝消息丢失与队列阻塞
spring boot·后端·rabbitmq
Java水解19 小时前
Spring Boot 视图层与模板引擎
spring boot·后端
Java水解20 小时前
一文搞懂 Spring Boot 默认数据库连接池 HikariCP
spring boot·后端
洋洋技术笔记1 天前
Spring Boot Web MVC配置详解
spring boot·后端
初次攀爬者2 天前
Kafka 基础介绍
spring boot·kafka·消息队列
用户8307196840822 天前
spring ai alibaba + nacos +mcp 实现mcp服务负载均衡调用实战
spring boot·spring·mcp
Java水解2 天前
SpringBoot3全栈开发实战:从入门到精通的完整指南
spring boot·后端
初次攀爬者3 天前
RocketMQ在Spring Boot上的基础使用
java·spring boot·rocketmq
花花无缺3 天前
搞懂@Autowired 与@Resuorce
java·spring boot·后端
Derek_Smart3 天前
从一次 OOM 事故说起:打造生产级的 JVM 健康检查组件
java·jvm·spring boot