📄 dbconnectionmanager.java
字号:
package net.ijsp.news.database;/** * DbConnectionBroker. * @version 1.0.13 3/12/02 * @author Marc A. Mnich */import java.io.*;import java.sql.*;import java.text.*;import java.util.Date;/** * DbConnectionBroker * A servlet-based broker for database connections. * Creates and manages a pool of database connections. * @version 1.0.13 3/12/02 * @author Marc A. Mnich */public class DBConnectionManager implements Runnable { private Thread runner; private Connection[] connPool; private int[] connStatus; private long[] connLockTime, connCreateDate; private String[] connID; private String dbDriver, dbServer, dbLogin, dbPassword, logFileString; private int currConnections, connLast, minConns, maxConns, maxConnMSec, maxCheckoutSeconds, debugLevel; //available: set to false on destroy, checked by getConnection() private boolean available=true; private PrintWriter log; private SQLWarning currSQLWarning; private String pid; private final int DEFAULTMAXCHECKOUTSECONDS=60; private final int DEFAULTDEBUGLEVEL=2; /** * Creates a new Connection Broker<br> * dbDriver: JDBC driver. e.g. 'oracle.jdbc.driver.OracleDriver'<br> * dbServer: JDBC connect string. e.g. 'jdbc:oracle:thin:@203.92.21.109:1526:orcl'<br> * dbLogin: Database login name. e.g. 'Scott'<br> * dbPassword: Database password. e.g. 'Tiger'<br> * minConns: Minimum number of connections to start with.<br> * maxConns: Maximum number of connections in dynamic pool.<br> * logFileString: Absolute path name for log file. e.g. 'c:/temp/mylog.log' <br> * maxConnTime: Time in days between connection resets. (Reset does a basic cleanup)<br> * logAppend: Append to logfile (optional)<br> * maxCheckoutSeconds: Max time a connection can be checked out before being recycled. Zero value turns option off, default is 60 seconds. * debugLevel: Level of debug messages output to the log file. 0 -> no messages, 1 -> Errors, 2 -> Warnings, 3 -> Information */ public DBConnectionManager(String dbDriver, String dbServer, String dbLogin, String dbPassword, int minConns, int maxConns, String logFileString, double maxConnTime) throws IOException { setupBroker(dbDriver, dbServer, dbLogin, dbPassword, minConns, maxConns, logFileString, maxConnTime, false, DEFAULTMAXCHECKOUTSECONDS, DEFAULTDEBUGLEVEL); } /* * Special constructor to handle logfile append */ public DBConnectionManager(String dbDriver, String dbServer, String dbLogin, String dbPassword, int minConns, int maxConns, String logFileString, double maxConnTime, boolean logAppend) throws IOException { setupBroker(dbDriver, dbServer, dbLogin, dbPassword, minConns, maxConns, logFileString, maxConnTime, logAppend, DEFAULTMAXCHECKOUTSECONDS, DEFAULTDEBUGLEVEL); } /* * Special constructor to handle connection checkout expiration */ public DBConnectionManager(String dbDriver, String dbServer, String dbLogin, String dbPassword, int minConns, int maxConns, String logFileString, double maxConnTime, boolean logAppend, int maxCheckoutSeconds, int debugLevel) throws IOException { setupBroker(dbDriver, dbServer, dbLogin, dbPassword, minConns, maxConns, logFileString, maxConnTime, logAppend, maxCheckoutSeconds, debugLevel); } private void setupBroker(String dbDriver, String dbServer, String dbLogin, String dbPassword, int minConns, int maxConns, String logFileString, double maxConnTime, boolean logAppend, int maxCheckoutSeconds, int debugLevel) throws IOException { connPool = new Connection[maxConns]; connStatus = new int[maxConns]; connLockTime = new long[maxConns]; connCreateDate = new long[maxConns]; connID = new String[maxConns]; currConnections = minConns; this.maxConns = maxConns; this.dbDriver = dbDriver; this.dbServer = dbServer; this.dbLogin = dbLogin; this.dbPassword = dbPassword; this.logFileString = logFileString; this.maxCheckoutSeconds = maxCheckoutSeconds; this.debugLevel = debugLevel; maxConnMSec = (int)(maxConnTime * 86400000.0); //86400 sec/day if(maxConnMSec < 30000) { // Recycle no less than 30 seconds. maxConnMSec = 30000; } try { log = new PrintWriter(new FileOutputStream(logFileString, logAppend),true); // Can't open the requested file. Open the default file. } catch (IOException e1) { try { log = new PrintWriter(new FileOutputStream("DCB_" + System.currentTimeMillis() + ".log", logAppend),true); } catch (IOException e2) { throw new IOException("Can't open any log file"); } } // Write the pid file (used to clean up dead/broken connection) SimpleDateFormat formatter = new SimpleDateFormat ("yyyy.MM.dd G 'at' hh:mm:ss a zzz"); Date nowc = new Date(); pid = formatter.format(nowc); BufferedWriter pidout = new BufferedWriter(new FileWriter(logFileString + "pid")); pidout.write(pid); pidout.close(); log.println("-----------------------------------------"); log.println("-----------------------------------------"); log.println("Starting DbConnectionBroker Version 1.0.13:"); log.println("dbDriver = " + dbDriver); log.println("dbServer = " + dbServer); log.println("dbLogin = " + dbLogin); log.println("log file = " + logFileString); log.println("minconnections = " + minConns); log.println("maxconnections = " + maxConns); log.println("Total refresh interval = " + maxConnTime + " days"); log.println("logAppend = " + logAppend); log.println("maxCheckoutSeconds = " + maxCheckoutSeconds); log.println("debugLevel = " + debugLevel); log.println("-----------------------------------------"); // Initialize the pool of connections with the mininum connections: // Problems creating connections may be caused during reboot when the // servlet is started before the database is ready. Handle this // by waiting and trying again. The loop allows 5 minutes for // db reboot. boolean connectionsSucceeded=false; int dbLoop=20; try { for(int i=1; i < dbLoop; i++) { try { for(int j=0; j < currConnections; j++) { createConn(j); } connectionsSucceeded=true; break; } catch (SQLException e){ if(debugLevel > 0) { log.println("--->Attempt (" + String.valueOf(i) + " of " + String.valueOf(dbLoop) + ") failed to create new connections set at startup: "); log.println(" " + e); log.println(" Will try again in 15 seconds..."); } try { Thread.sleep(15000); } catch(InterruptedException e1) {} } } if(!connectionsSucceeded) { // All attempts at connecting to db exhausted if(debugLevel > 0) { log.println("\r\nAll attempts at connecting to Database exhausted"); } throw new IOException(); } } catch (Exception e) { throw new IOException(); } // Fire up the background housekeeping thread runner = new Thread(this); runner.start(); }//End DbConnectionBroker() /** * Housekeeping thread. Runs in the background with low CPU overhead. * Connections are checked for warnings and closure and are periodically * restarted. * This thread is a catchall for corrupted * connections and prevents the buildup of open cursors. (Open cursors * result when the application fails to close a Statement). * This method acts as fault tolerance for bad connection/statement programming. */ public void run() { boolean forever = true; Statement stmt=null; String currCatalog=null; long maxCheckoutMillis = maxCheckoutSeconds * 1000; while(forever) { // Make sure the log file is the one this instance opened // If not, clean it up! try { BufferedReader in = new BufferedReader(new FileReader(logFileString + "pid")); String curr_pid = in.readLine(); if(curr_pid.equals(pid)) { //log.println("They match = " + curr_pid); } else { //log.println("No match = " + curr_pid); log.close(); // Close all connections silently - they are definitely dead. for(int i=0; i < currConnections; i++) { try { connPool[i].close(); } catch (SQLException e1) {} // ignore } // Returning from the run() method kills the thread return; } in.close(); } catch (IOException e1) { log.println("Can't read the file for pid info: " + logFileString + "pid"); } // Get any Warnings on connections and print to event file for(int i=0; i < currConnections; i++) { try { currSQLWarning = connPool[i].getWarnings(); if(currSQLWarning != null) { if(debugLevel > 1) { log.println("Warnings on connection " + String.valueOf(i) + " " + currSQLWarning); } connPool[i].clearWarnings(); } } catch(SQLException e) { if(debugLevel > 1) { log.println("Cannot access Warnings: " + e); } } } for(int i=0; i < currConnections; i++) { // Do for each connection long age = System.currentTimeMillis() - connCreateDate[i]; try { // Test the connection with createStatement call synchronized(connStatus) { if(connStatus[i] > 0) { // In use, catch it next time! // Check the time it's been checked out and recycle long timeInUse = System.currentTimeMillis() - connLockTime[i]; if(debugLevel > 2) { log.println("Warning. Connection " + i + " in use for " + timeInUse + " ms"); } if(maxCheckoutMillis != 0) { if(timeInUse > maxCheckoutMillis) { if(debugLevel > 1) { log.println("Warning. Connection " + i + " failed to be returned in time. Recycling..."); } throw new SQLException(); } } continue; } connStatus[i] = 2; // Take offline (2 indicates housekeeping lock) } if(age > maxConnMSec) { // Force a reset at the max conn time throw new SQLException(); } stmt = connPool[i].createStatement(); connStatus[i] = 0; // Connection is O.K. //log.println("Connection confirmed for conn = " + // String.valueOf(i)); // Some DBs return an object even if DB is shut down if(connPool[i].isClosed()) { throw new SQLException(); } // Connection has a problem, restart it } catch(SQLException e) { if(debugLevel > 1) { log.println(new Date().toString() + " ***** Recycling connection " + String.valueOf(i) + ":"); } try { connPool[i].close(); } catch(SQLException e0) { if(debugLevel > 0) { log.println("Error! Can't close connection! Might have been closed already. Trying to recycle anyway... (" + e0 + ")"); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -