给log4j配上数据库连接池

2023-12-02 08:08

本文主要是介绍给log4j配上数据库连接池,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

              给log4j配上数据库连接池

http://www.javaresearch.org/article/41776.htm

我们都知道log4j是一个优秀的开源日志记录项目,我们不仅可以对输出的日志的格式自

定义,还可以自己定义日志输出的目的地,比如:屏幕,文本文件,数据库,甚至能通过socket输出。

        现在让我们对日志输出到数据库来进行配置

         配置如下:

#---JDBC ---输出到数据库

# JDBCAppender log4j.properties file

#log4j.rootCategory=WARN,JDBC

# APPENDER JDBC

log4j.appender.JDBC=org.apache.log4j.jdbc.JDBCAppender

log4j.appender.JDBC.driver=com.mysql.jdbc.Driver

log4j.appender.JDBC.URL=jdbc:mysql://localhost:3306/test

log4j.appender.JDBC.user=use

log4j.appender.JDBC.password=password

log4j.appender.JDBC.layout=org.apache.log4j.PatternLayout

log4j.appender.JDBC.sql=INSERT INTO LOGGING (log_date, log_level, location, message) VALUES ('%d{ISO8601}', '%-5p', '%C,%L', '%m')

表结构如下:

log_date   varchar2(50)

log_level  varchar2(5)

location   varchar2(100)  

message    varchar2(1000)

笔者照做,但没有运行成功,而且此种方法是利用传统的数据库连接方法,对于数据库的管理和效率严重不足,在现在这个连接池横行的时代,为什么我们不能给给Log4j配上连接池,让Log4j利用数据连接池的连接和数据库进行通讯。现查看Log4j的Api,发现JDBCAppender这个类有以下几段话:WARNING: This version of JDBCAppender is very likely to be completely replaced in the future. Moreoever, it does not log exceptions. The JDBCAppender provides for sending log events to a database. 

For use as a base class: 

Override getConnection() to pass any connection you want. Typically this is used to enable application wide connection pooling. 

Override closeConnection(Connection con) -- if you override getConnection make sure to implement closeConnection to handle the connection you generated. Typically this would return the connection to the pool it came from. 

Override getLogStatement(LoggingEvent event) to produce specialized or dynamic statements. The default uses the sql option value.

原来log4j建议我们把其提供的JDBCAppender作为基类来使用,然后Override三个父类的方法:getConnection(),closeConnection(Connection con)和getLogStatement(LoggingEvent event)。

原来如此,那就写一个子类JDBCPoolAppender来替代这个JDBCAppender

JDBCPoolAppender代码和其相关代码如下:

JDBCPoolAppender.java:

package common.log;

import java.sql.Connection;

import org.apache.log4j.spi.LoggingEvent;

import java.sql.SQLException;

import java.sql.Statement;

import java.util.Iterator;

import org.apache.log4j.spi.ErrorCode;

import org.apache.log4j.PatternLayout;

import common.sql.MyDB;

import common.sql.GeneralDb;

public class JDBCPoolAppender extends org.apache.log4j.jdbc.JDBCAppender {

    

    private MyDB mydb = null;  

    protected String sqlname=""; //增加一个数据库jndiName的属性

    protected Connection connection = null;

    protected String sqlStatement = "";

    /**

     * size of LoggingEvent buffer before writting to the database.

     * Default is 1.

     */

    protected int bufferSize = 1;

    public JDBCPoolAppender() {

        super();

    }

    /**

     * ArrayList holding the buffer of Logging Events.

     */

    public void append(LoggingEvent event) {

        buffer.add(event);

        if (buffer.size() >= bufferSize)

            flushBuffer();

    }

    /**

     * By default getLogStatement sends the event to the required Layout object.

     * The layout will format the given pattern into a workable SQL string.

     *

     * Overriding this provides direct access to the LoggingEvent

     * when constructing the logging statement.

     *

     */

    protected String getLogStatement(LoggingEvent event) {

        return getLayout().format(event);

    }

    /**

     *

     * Override this to provide an alertnate method of getting

     * connections (such as caching).  One method to fix this is to open

     * connections at the start of flushBuffer() and close them at the

     * end.  I use a connection pool outside of JDBCAppender which is

     * accessed in an override of this method.

     * */

    protected void execute(String sql) throws SQLException {

        Connection con = null;

        Statement stmt = null;

        try {

            con = getConnection();

            stmt = con.createStatement();

            stmt.executeUpdate(sql);

        } catch (SQLException e) {

            if (stmt != null)

                stmt.close();

            throw e;

        }

        stmt.close();

        closeConnection(con);

        //System.out.println("Execute: " + sql);

    }

    /**

     * Override this to return the connection to a pool, or to clean up the

     * resource.

     *

     * The default behavior holds a single connection open until the appender

     * is closed (typically when garbage collected).

     */

    protected void closeConnection(Connection con) {

        mydb=null;  

        try {

           if (connection != null && !connection.isClosed())

               connection.close();

       } catch (SQLException e) {

           errorHandler.error("Error closing connection", e,

                              ErrorCode.GENERIC_FAILURE);

       }

    }

    /**

     * Override 此函数来利用连接池返回一个Connetion对象

     *    

     */

    protected Connection getConnection() throws SQLException {  

        try {

            mydb = GeneralDb.getInstance(sqlname);  

            connection = mydb.getConnection();     

       } catch (Exception e) {

            errorHandler.error("Error opening connection", e, ErrorCode.GENERIC_FAILURE);

        }

        return connection;

    }

    /**

     * Closes the appender, flushing the buffer first then closing the default

     * connection if it is open.

     */

    public void close() {

        flushBuffer();

        try {

            if (connection != null && !connection.isClosed())

                connection.close();

        } catch (SQLException e) {

            errorHandler.error("Error closing connection", e,

                               ErrorCode.GENERIC_FAILURE);

        }

        this.closed = true;

    }

    /**

     * loops through the buffer of LoggingEvents, gets a

     * sql string from getLogStatement() and sends it to execute().

     * Errors are sent to the errorHandler.

     *

     * If a statement fails the LoggingEvent stays in the buffer!

     */

    public void flushBuffer() {

        //Do the actual logging

        removes.ensureCapacity(buffer.size());

        for (Iterator i = buffer.iterator(); i.hasNext(); ) {

            try {

                LoggingEvent logEvent = (LoggingEvent) i.next();

                String sql = getLogStatement(logEvent);

                execute(sql);

                removes.add(logEvent);

            } catch (SQLException e) {

                errorHandler.error("Failed to excute sql", e,

                                   ErrorCode.FLUSH_FAILURE);

            }

        }

        // remove from the buffer any events that were reported

        buffer.removeAll(removes);

        // clear the buffer of reported events

        removes.clear();

    }

    /** closes the appender before disposal */

    public void finalize() {

        close();

    }

    /**

     * JDBCAppender requires a layout.

     * */

    public boolean requiresLayout() {

        return true;

    }

    /**

     *

     */

    public void setSql(String s) {

        sqlStatement = s;

        if (getLayout() == null) {

            this.setLayout(new PatternLayout(s));

        } else {

            ((PatternLayout) getLayout()).setConversionPattern(s);

        }

    }

    /**

     * Returns pre-formated statement eg: insert into LogTable (msg) values ("%m")

     */

    public String getSql() {

        return sqlStatement;

    }

    public void setSqlname(String sqlname){

        sqlname=sqlname;

    }

    

    public String getSqlname(){

        return sqlname;

    }    

    public void setBufferSize(int newBufferSize) {

        bufferSize = newBufferSize;

        buffer.ensureCapacity(bufferSize);

        removes.ensureCapacity(bufferSize);

    }

   

    public int getBufferSize() {

        return bufferSize;

    }

}

MyDB.java:

package common.sql;

import java.sql.*;

import com.codestudio.sql.*;  //引入开源项目Poolman数据库连接池的包

public class MyDB {

    public static final String module = MyDB.class.getName();

    private String dbName = "";

    private PoolMan plmn = null;

    public MyDB(String dbName) {

        try {

            if (plmn == null) {

                plmn = (PoolMan) Class.forName("com.codestudio.sql.PoolMan").

                        newInstance();

            }

        } catch (Exception ec) {

           System.out.println(ec.toString()+module);

        }

        this.dbName = dbName;

    }

    private Connection getNewConnection() {

        Connection conn = null;

        try {

            conn = plmn.connect("jdbc:poolman://" + dbName);  

            conn.setAutoCommit(true);

        } catch (Exception ec) {

            System.out.println(ec.toString()+"First:Connect sqlsever failed"+module);

            try {

                Thread.sleep(1000);

                conn = plmn.connect("jdbc:poolman://" + dbName);

                conn.setAutoCommit(true);

            } catch (Exception ecs) {

               System.out.println(ecs.toString()+"Again:Connect sqlsever faile"+module);

            }

        }

        return conn;

    }

    public Connection getConnection() {

        return getNewConnection();

    }

}

GeneralDb.java:

package common.sql;

package common.sql; 

import java.util.*;

public class GeneralDb {

    private static Hashtable dbPool; 

    public static MyDB getInstance(String dbname) {

        if (dbPool == null) {

            dbPool = new Hashtable();

        }

        MyDB db = (MyDB) dbPool.get(dbname);

        if (db == null) {

            db = new MyDB(dbname);

            dbPool.put(dbname, db); 

        }

        return db;

    }

}

Log4j数据库连接池的配置如下:

log4j.appender.JDBC=common.log.JDBCPoolAppender 

log4j.appender.JDBC.sqlname=log

log4j.appender.JDBC.layout=org.apache.log4j.PatternLayout

log4j.appender.JDBC.sql=INSERT INTO LOGGING (log_date, log_level, location, message) VALUES ('%d{ISO8601}', '%-5p', '%C,%L', '%m')

poolman.xml配置如下:

〈?xml version="1.0" encoding="UTF-8"?>

〈poolman>

  〈management-mode>local〈/management-mode>

  〈datasource>

    〈dbname>log〈/dbname>

    〈jndiName>log〈/jndiName>

    〈driver>com.mysql.jdbc.Driver〈/driver>

    〈url>jdbc:mysql://localhost:3306/test〈/url>

    〈username>use〈/username>

    〈password>password〈/password>

    〈minimumSize>0〈/minimumSize>

    〈maximumSize>10〈/maximumSize>

    〈logFile>logs/mysql.log〈/logFile>

  〈/datasource>

〈/poolman>

    

运行成功!对于JDBCPoolAppender的属性(比如sqlname属性)我们可以利用Log4j的反射机制随便添加,只要在配置文件给其附上值即可应用,而原来的父类里面的一些属性(username什么的)和其get,set方法由于在连接池中不需要,所以删除。而在JDBCPoolAppender类中,我也只是将getConnection 方法Override ,在这个方法中我们可以根据需要生成我们的Connection对象,另外两个方法大家可以根据需求来决定怎样Override。 

这篇关于给log4j配上数据库连接池的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/444563

相关文章

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

MySQL数据库宕机,启动不起来,教你一招搞定!

作者介绍:老苏,10余年DBA工作运维经验,擅长Oracle、MySQL、PG、Mongodb数据库运维(如安装迁移,性能优化、故障应急处理等)公众号:老苏畅谈运维欢迎关注本人公众号,更多精彩与您分享。 MySQL数据库宕机,数据页损坏问题,启动不起来,该如何排查和解决,本文将为你说明具体的排查过程。 查看MySQL error日志 查看 MySQL error日志,排查哪个表(表空间

深入理解数据库的 4NF:多值依赖与消除数据异常

在数据库设计中, "范式" 是一个常常被提到的重要概念。许多初学者在学习数据库设计时,经常听到第一范式(1NF)、第二范式(2NF)、第三范式(3NF)以及 BCNF(Boyce-Codd范式)。这些范式都旨在通过消除数据冗余和异常来优化数据库结构。然而,当我们谈到 4NF(第四范式)时,事情变得更加复杂。本文将带你深入了解 多值依赖 和 4NF,帮助你在数据库设计中消除更高级别的异常。 什么是

如何确定 Go 语言中 HTTP 连接池的最佳参数?

确定 Go 语言中 HTTP 连接池的最佳参数可以通过以下几种方式: 一、分析应用场景和需求 并发请求量: 确定应用程序在特定时间段内可能同时发起的 HTTP 请求数量。如果并发请求量很高,需要设置较大的连接池参数以满足需求。例如,对于一个高并发的 Web 服务,可能同时有数百个请求在处理,此时需要较大的连接池大小。可以通过压力测试工具模拟高并发场景,观察系统在不同并发请求下的性能表现,从而

DM8数据库安装后配置

1 前言 在上篇文章中,我们已经成功将库装好。在安装完成后,为了能够更好地满足应用需求和保障系统的安全稳定运行,通常需要进行一些基本的配置。下面是一些常见的配置项: 数据库服务注册:默认包含14个功能模块,将这些模块注册成服务后,可以更好的启动和管理这些功能;基本的实例参数配置:契合应用场景和发挥系统的最大性能;备份:有备无患;… 2 注册实例服务 注册了实例服务后,可以使用系统服务管理,

速了解MySQL 数据库不同存储引擎

快速了解MySQL 数据库不同存储引擎 MySQL 提供了多种存储引擎,每种存储引擎都有其特定的特性和适用场景。了解这些存储引擎的特性,有助于在设计数据库时做出合理的选择。以下是 MySQL 中几种常用存储引擎的详细介绍。 1. InnoDB 特点: 事务支持:InnoDB 是一个支持 ACID(原子性、一致性、隔离性、持久性)事务的存储引擎。行级锁:使用行级锁来提高并发性,减少锁竞争

开源分布式数据库中间件

转自:https://www.csdn.net/article/2015-07-16/2825228 MyCat:开源分布式数据库中间件 为什么需要MyCat? 虽然云计算时代,传统数据库存在着先天性的弊端,但是NoSQL数据库又无法将其替代。如果传统数据易于扩展,可切分,就可以避免单机(单库)的性能缺陷。 MyCat的目标就是:低成本地将现有的单机数据库和应用平滑迁移到“云”端

ORACLE 11g 创建数据库时 Enterprise Manager配置失败的解决办法 无法打开OEM的解决办法

在win7 64位系统下安装oracle11g,在使用Database configuration Assistant创建数据库时,在创建到85%的时候报错,错误如下: 解决办法: 在listener.ora中增加对BlueAeri-PC或ip地址的侦听,具体步骤如下: 1.启动Net Manager,在“监听程序”--Listener下添加一个地址,主机名写计

MyBatis 切换不同的类型数据库方案

下属案例例当前结合SpringBoot 配置进行讲解。 背景: 实现一个工程里面在部署阶段支持切换不同类型数据库支持。 方案一 数据源配置 关键代码(是什么数据库,该怎么配就怎么配) spring:datasource:name: test# 使用druid数据源type: com.alibaba.druid.pool.DruidDataSource# @需要修改 数据库连接及驱动u

CentOS下mysql数据库data目录迁移

https://my.oschina.net/u/873762/blog/180388        公司新上线一个资讯网站,独立主机,raid5,lamp架构。由于资讯网是面向小行业,初步估计一两年内访问量压力不大,故,在做服务器系统搭建的时候,只是简单分出一个独立的data区作为数据库和网站程序的专区,其他按照linux的默认分区。apache,mysql,php均使用yum安装(也尝试