📄 dbconnectionmanager.java
字号:
package net.ijsp.download.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 + -