早餐2塊2

          if(!java.isExist()) boss.fireOut(me);

          統計

          留言簿(1)

          積分與排名

          閱讀排行榜

          評論排行榜

          給Log4j配上數據庫連接池

                 作者:  早餐2塊2 

                 我們都知道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;

          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。:)
                      


           

          posted on 2005-11-04 16:24 早餐2塊2 閱讀(658) 評論(0)  編輯  收藏 所屬分類: java基礎

          主站蜘蛛池模板: 大兴区| 仁布县| 满城县| 南乐县| 黄梅县| 长汀县| 定西市| 虎林市| 桐乡市| 横山县| 平泉县| 康平县| 佛山市| 肥乡县| 五常市| 桦南县| 宝丰县| 全州县| 晋宁县| 彭山县| 通江县| 蓝田县| 云龙县| 饶平县| 屯昌县| 栖霞市| 神池县| 巴青县| 博兴县| 永年县| 海兴县| 临泉县| 龙陵县| 双城市| 嘉黎县| 泸水县| 当雄县| 大荔县| 丁青县| 甘洛县| 克拉玛依市|