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的连接池管理
最终验证
- 启动应用前,先编写测试类验证数据库连接是否正常:
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("数据库连接成功"); } } }
- 测试通过后启动应用,检查日志是否正常写入Oracle数据库。
内容的提问来源于stack exchange,提问作者tejashree parab
相关产品推荐
相关产品推荐

