SLF4J+Log4j2日志存入MySQL配置教程

2026-06-16阅读 0热度 0
其他

在Springboot项目中配置日志持久化至数据库时,我踩过不少坑。尝试多种方案后,发现Log4j2的JDBC Appender确实高效可靠。

项目基于Springboot 2.2.3.RELEASE,日志门面选用SLF4J 1.7.30,实现框架搭配JUL与Log4j 2.12.1(务必排除自带的Logback)。同时需要引入log4j-slf4j桥接包,版本同样锁定2.12.1。

参照官方文档,整体实现逻辑非常清晰。

文档直言核心在于获取一个有效的java.sql.Connection,并提供了可直接复用的配置模板。

Appenders配置详解

先看Appenders部分的配置。关键属性包括:tableName指定目标表名,class定义获取Connection的工厂类,method指明工厂类中的方法名。

每个Column标签支持三种模式:literal直接写入SQL字面量(如数据库序列值),pattern从日志事件中提取字段,isEventTimestamp用于标记时间戳列。

配置示例:



    
        
            
            
            
            
            
            
            
        
    
    
        
            
        
    

Connection获取实战

官方示例使用Apache DBCP连接池实现Connection获取。关键在于Log4j2仅负责调用你提供的工厂方法,连接池管理、事务控制、自动重连等全部需要自行实现。

示例代码:

package net.example.db;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

import javax.sql.DataSource;

import org.apache.commons.dbcp.DriverManagerConnectionFactory;
import org.apache.commons.dbcp.PoolableConnection;
import org.apache.commons.dbcp.PoolableConnectionFactory;
import org.apache.commons.dbcp.PoolingDataSource;
import org.apache.commons.pool.impl.GenericObjectPool;

public class ConnectionFactory {
    private static interface Singleton {
        final ConnectionFactory INSTANCE = new ConnectionFactory();
    }

    private final DataSource dataSource;

    private ConnectionFactory() {
        Properties properties = new Properties();
        properties.setProperty("user", "logging");
        properties.setProperty("password", "abc123");

        GenericObjectPool pool = new GenericObjectPool();
        DriverManagerConnectionFactory connectionFactory = new DriverManagerConnectionFactory(
                "jdbc:mysql://example.org:3306/exampleDb", properties);
        new PoolableConnectionFactory(connectionFactory, pool, null, "SELECT 1", 3, false, false,
                Connection.TRANSACTION_READ_COMMITTED);

        this.dataSource = new PoolingDataSource(pool);
    }

    public static Connection getDatabaseConnection() throws SQLException {
        return Singleton.INSTANCE.dataSource.getConnection();
    }
}

到这里配置似乎完成了,但先别急着收工,有几个关键陷阱必须提前规避。

第一,Log4j2虽然给出了连接池参考,但它本身不管理连接池生命周期、事务边界和断线重连。这意味着你提供的工厂方法必须在任何场景下都能返回有效连接。一旦连接被关闭,框架不会自动恢复,需要自己编写判活与重建逻辑。

第二,实际项目中最常见的问题:很多项目已集成Druid等连接池,但Log4j2写入日志时,这些连接池可能尚未完成初始化(或者加载顺序错位)。结果日志无法写入,异常还被静默吞掉。务必规划好Bean的加载时序。

这里分享一个我在生产环境中使用的简化实现,比官方DBCP示例更直观:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class ConnectionFactory {
    private static Connection connection = null;

    public static Connection getDatabaseConnection() {
        try {
            if (connection == null || connection.isClosed()) {
                synchronized (ConnectionFactory.class) {
                    if (connection == null || connection.isClosed()) {
                        connection = DriverManager.getConnection(
                            "jdbc:mysql://**.**.cn:3306/**?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai",
                            "**", "**");
                    }
                }
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return connection;
    }
}

配套建表SQL简洁直观:

create table tbl_log (
    ID int auto_increment primary key,
    EVENT_DATE datetime null,
    LEVEL varchar(20) null,
    LOGGER varchar(20) null,
    MESSAGE text null,
    THROWABLE text null
);

最后查看实际运行效果:

整体思路并不复杂,但细节疏忽极易翻车。尤其框架加载顺序与连接有效性管理,强烈建议在正式环境反复压测后再部署上线。

免责声明

本网站新闻资讯均来自公开渠道,力求准确但不保证绝对无误,内容观点仅代表作者本人,与本站无关。若涉及侵权,请联系我们处理。本站保留对声明的修改权,最终解释权归本站所有。

相关阅读

更多
欢迎回来 登录或注册后,可保存提示词和历史记录
登录后可同步收藏、历史记录和常用模板
注册即表示同意服务条款与隐私政策