You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Log4j2异步JDBC Appender无法写入数据库问题求助

解决Log4j2异步JDBC Appender写入Oracle数据库失败问题

核心错误分析

错误日志明确指出JDBC connection not available,根源在于自定义ConnectionFactory实现存在致命问题,导致无法创建有效的数据库连接,同时Spring与Log4j2的整合方式也存在缺陷。

具体问题与修复方案

1. ConnectionFactory递归调用导致无法创建数据源

原dataSource()方法最后一行return dataSource();是递归调用,会直接引发栈溢出错误,永远无法返回有效的DataSource实例。

修复代码:

@Bean
public DataSource dataSource() throws SQLException {
    OracleDataSource dataSource = new OracleDataSource();
    dataSource.setURL(url);
    dataSource.setUser(username);
    dataSource.setPassword(password);
    dataSource.setImplicitCachingEnabled(true);
    dataSource.setFastConnectionFailoverEnabled(true);
    dataSource.setDriverType(driver);
    return dataSource; // 改为返回创建好的对象,而非递归调用方法
}

2. 手动实例化ConnectionFactory导致Spring注解失效

原代码通过内部Singleton接口手动new ConnectionFactory(),该实例不受Spring容器管理,@Value注解无法注入application.properties中的配置值,导致url、username等参数均为null,无法创建有效连接。

修复方案:让ConnectionFactory受Spring管理

  • 给ConnectionFactory添加@Component注解,让Spring扫描并创建单例Bean
  • 移除手动Singleton实现,通过Spring上下文获取Bean实例

修改后的ConnectionFactory:

import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import oracle.jdbc.pool.OracleDataSource;

@Component
public class ConnectionFactory {
    
    @Value("${spring.datasource.url}")
    private String url;

    @Value("${spring.datasource.username}")
    private String username;

    @Value("${spring.datasource.password}")
    private String password;

    @Value("${spring.datasource.driver-class-name}")
    private String driver;

    private DataSource dataSource;

    // 初始化数据源
    public DataSource getDataSource() throws SQLException {
        if (dataSource == null) {
            OracleDataSource oracleDataSource = new OracleDataSource();
            oracleDataSource.setURL(url);
            oracleDataSource.setUser(username);
            oracleDataSource.setPassword(password);
            oracleDataSource.setImplicitCachingEnabled(true);
            oracleDataSource.setFastConnectionFailoverEnabled(true);
            oracleDataSource.setDriverType(driver);
            dataSource = oracleDataSource;
        }
        return dataSource;
    }

    public static Connection getDatabaseConnection() throws SQLException {
        // 通过Spring上下文获取受管理的ConnectionFactory实例
        return SpringContextHolder.getBean(ConnectionFactory.class).getDataSource().getConnection();
    }
}

新增Spring上下文持有类,用于获取Spring管理的Bean:

import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class SpringContextHolder implements ApplicationContextAware {
    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        SpringContextHolder.applicationContext = applicationContext;
    }

    public static <T> T getBean(Class<T> clazz) {
        return applicationContext.getBean(clazz);
    }
}

3. 完善Log4j2依赖配置

原依赖仅引入log4j-core,缺少Spring Boot与Log4j2的整合依赖,容易导致版本冲突和整合问题。替换为Spring Boot官方提供的Log4j2 starter:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>

该依赖会自动引入log4j-core、log4j-api等必要组件,并保证与Spring Boot版本兼容。

4. 验证数据库表结构匹配

确保LOG_TABLE的字段类型与日志字段兼容:

  • LOG_LEVEL、CLASS_NAME、METHOD_NAME、MESSAGE、THREAD_NAME:字符类型(如VARCHAR2)
  • LINE_NUMBER:数字类型(如NUMBER)
  • TIMESTAMP:日期时间类型(如TIMESTAMP)

5. 简化配置(可选)

无需手动实现DataSource,直接使用Spring Boot自动配置的DataSource:

  • 移除ConnectionFactory中的DataSource创建逻辑,改为@Autowired注入Spring自动配置的DataSource
  • 这样可以避免手动配置OracleDataSource的繁琐,同时利用Spring的连接池管理

最终验证

  1. 启动应用前,先编写测试类验证数据库连接是否正常:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.junit.jupiter.api.Test;
import javax.sql.DataSource;
import java.sql.Connection;

@SpringBootTest
public class DatabaseConnectionTest {
    @Autowired
    private DataSource dataSource;

    @Test
    public void testConnection() throws Exception {
        try (Connection conn = dataSource.getConnection()) {
            System.out.println("数据库连接成功");
        }
    }
}
  1. 测试通过后启动应用,检查日志是否正常写入Oracle数据库。

内容的提问来源于stack exchange,提问作者tejashree parab

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 10:02:36