给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

相关文章

Python调用Orator ORM进行数据库操作

《Python调用OratorORM进行数据库操作》OratorORM是一个功能丰富且灵活的PythonORM库,旨在简化数据库操作,它支持多种数据库并提供了简洁且直观的API,下面我们就... 目录Orator ORM 主要特点安装使用示例总结Orator ORM 是一个功能丰富且灵活的 python O

使用 sql-research-assistant进行 SQL 数据库研究的实战指南(代码实现演示)

《使用sql-research-assistant进行SQL数据库研究的实战指南(代码实现演示)》本文介绍了sql-research-assistant工具,该工具基于LangChain框架,集... 目录技术背景介绍核心原理解析代码实现演示安装和配置项目集成LangSmith 配置(可选)启动服务应用场景

使用Navicat工具比对两个数据库所有表结构的差异案例详解

《使用Navicat工具比对两个数据库所有表结构的差异案例详解》:本文主要介绍如何使用Navicat工具对比两个数据库test_old和test_new,并生成相应的DDLSQL语句,以便将te... 目录概要案例一、如图两个数据库test_old和test_new进行比较:二、开始比较总结概要公司存在多

MySQL数据库函数之JSON_EXTRACT示例代码

《MySQL数据库函数之JSON_EXTRACT示例代码》:本文主要介绍MySQL数据库函数之JSON_EXTRACT的相关资料,JSON_EXTRACT()函数用于从JSON文档中提取值,支持对... 目录前言基本语法路径表达式示例示例 1: 提取简单值示例 2: 提取嵌套值示例 3: 提取数组中的值注意

查询SQL Server数据库服务器IP地址的多种有效方法

《查询SQLServer数据库服务器IP地址的多种有效方法》作为数据库管理员或开发人员,了解如何查询SQLServer数据库服务器的IP地址是一项重要技能,本文将介绍几种简单而有效的方法,帮助你轻松... 目录使用T-SQL查询方法1:使用系统函数方法2:使用系统视图使用SQL Server Configu

SQL Server数据库迁移到MySQL的完整指南

《SQLServer数据库迁移到MySQL的完整指南》在企业应用开发中,数据库迁移是一个常见的需求,随着业务的发展,企业可能会从SQLServer转向MySQL,原因可能是成本、性能、跨平台兼容性等... 目录一、迁移前的准备工作1.1 确定迁移范围1.2 评估兼容性1.3 备份数据二、迁移工具的选择2.1

Python中连接不同数据库的方法总结

《Python中连接不同数据库的方法总结》在数据驱动的现代应用开发中,Python凭借其丰富的库和强大的生态系统,成为连接各种数据库的理想编程语言,下面我们就来看看如何使用Python实现连接常用的几... 目录一、连接mysql数据库二、连接PostgreSQL数据库三、连接SQLite数据库四、连接Mo

Oracle数据库如何切换登录用户(system和sys)

《Oracle数据库如何切换登录用户(system和sys)》文章介绍了如何使用SQL*Plus工具登录Oracle数据库的system用户,包括打开登录入口、输入用户名和口令、以及切换到sys用户的... 目录打开登录入口登录system用户总结打开登录入口win+R打开运行对话框,输php入:sqlp

数据库使用之union、union all、各种join的用法区别解析

《数据库使用之union、unionall、各种join的用法区别解析》:本文主要介绍SQL中的Union和UnionAll的区别,包括去重与否以及使用时的注意事项,还详细解释了Join关键字,... 目录一、Union 和Union All1、区别:2、注意点:3、具体举例二、Join关键字的区别&php

查询Oracle数据库表是否被锁的实现方式

《查询Oracle数据库表是否被锁的实现方式》本文介绍了查询Oracle数据库表是否被锁的方法,包括查询锁表的会话、人员信息,根据object_id查询表名,以及根据会话ID查询和停止本地进程,同时,... 目录查询oracle数据库表是否被锁1、查询锁表的会话、人员等信息2、根据 object_id查询被