给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

相关文章

JavaWeb项目创建、部署、连接数据库保姆级教程(tomcat)

《JavaWeb项目创建、部署、连接数据库保姆级教程(tomcat)》:本文主要介绍如何在IntelliJIDEA2020.1中创建和部署一个JavaWeb项目,包括创建项目、配置Tomcat服务... 目录简介:一、创建项目二、tomcat部署1、将tomcat解压在一个自己找得到路径2、在idea中添加

MySQL MHA集群详解(数据库高可用)

《MySQLMHA集群详解(数据库高可用)》MHA(MasterHighAvailability)是开源MySQL高可用管理工具,用于自动故障检测与转移,支持异步或半同步复制的MySQL主从架构,本... 目录mysql 高可用方案:MHA 详解与实战1. MHA 简介2. MHA 的组件组成(1)MHA

MySQL 数据库进阶之SQL 数据操作与子查询操作大全

《MySQL数据库进阶之SQL数据操作与子查询操作大全》本文详细介绍了SQL中的子查询、数据添加(INSERT)、数据修改(UPDATE)和数据删除(DELETE、TRUNCATE、DROP)操作... 目录一、子查询:嵌套在查询中的查询1.1 子查询的基本语法1.2 子查询的实战示例二、数据添加:INSE

通过DBeaver连接GaussDB数据库的实战案例

《通过DBeaver连接GaussDB数据库的实战案例》DBeaver是一个通用的数据库客户端,可以通过配置不同驱动连接各种不同的数据库,:本文主要介绍通过DBeaver连接GaussDB数据库的... 目录​一、前置条件​二、连接步骤​三、常见问题与解决方案​1. 驱动未找到​2. 连接超时​3. 权限不

MySQL数据库读写分离与负载均衡的实现逻辑

《MySQL数据库读写分离与负载均衡的实现逻辑》读写分离与负载均衡是数据库优化的关键策略,读写分离的核心是将数据库的读操作与写操作分离,本文给大家介绍MySQL数据库读写分离与负载均衡的实现方式,感兴... 目录读写分离与负载均衡的核心概念与目的读写分离的必要性与实现逻辑读写分离的实现方式及优缺点读负载均衡

Go语言中如何进行数据库查询操作

《Go语言中如何进行数据库查询操作》在Go语言中,与数据库交互通常通过使用数据库驱动来实现,Go语言支持多种数据库,如MySQL、PostgreSQL、SQLite等,每种数据库都有其对应的官方或第三... 查询函数QueryRow和Query详细对比特性QueryRowQuery返回值数量1个:*sql

Mysql数据库聚簇索引与非聚簇索引举例详解

《Mysql数据库聚簇索引与非聚簇索引举例详解》在MySQL中聚簇索引和非聚簇索引是两种常见的索引结构,它们的主要区别在于数据的存储方式和索引的组织方式,:本文主要介绍Mysql数据库聚簇索引与非... 目录前言一、核心概念与本质区别二、聚簇索引(Clustered Index)1. 实现原理(以 Inno

MySQL数据库双机热备的配置方法详解

《MySQL数据库双机热备的配置方法详解》在企业级应用中,数据库的高可用性和数据的安全性是至关重要的,MySQL作为最流行的开源关系型数据库管理系统之一,提供了多种方式来实现高可用性,其中双机热备(M... 目录1. 环境准备1.1 安装mysql1.2 配置MySQL1.2.1 主服务器配置1.2.2 从

SpringBoot基于注解实现数据库字段回填的完整方案

《SpringBoot基于注解实现数据库字段回填的完整方案》这篇文章主要为大家详细介绍了SpringBoot如何基于注解实现数据库字段回填的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以了解... 目录数据库表pom.XMLRelationFieldRelationFieldMapping基础的一些代

使用Node.js和PostgreSQL构建数据库应用

《使用Node.js和PostgreSQL构建数据库应用》PostgreSQL是一个功能强大的开源关系型数据库,而Node.js是构建高效网络应用的理想平台,结合这两个技术,我们可以创建出色的数据驱动... 目录初始化项目与安装依赖建立数据库连接执行CRUD操作查询数据插入数据更新数据删除数据完整示例与最佳