📄 dbconnectiondefaultpool.java
字号:
*
* DbConnectionBroker
* A servlet-based broker for database connections.
* Creates and manages a pool of database connections.
* @version 1.0.11 12/7/99
* @author Marc A. Mnich
*/
private class ConnectionPool 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;
//available: set to false on destroy, checked by getConnection()
private boolean available=true;
private PrintWriter log;
private SQLWarning currSQLWarning;
private String pid;
/**
* 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>
*/
public ConnectionPool (String dbDriver, String dbServer, String dbLogin,
String dbPassword, int minConns, int maxConns,
String logFileString, double maxConnTime) 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;
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),true);
// Can't open the requested file. Open the default file.
}
catch (IOException e1) {
System.err.println("Warning: DbConnectionDefaultPool could not open \""
+ logFileString + "\" to write log to. Make sure that your Java " +
"process has permission to write to the file and that the directory exists."
);
try {
log = new PrintWriter(new FileOutputStream("DCB_" +
System.currentTimeMillis() + ".log"), 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");
java.util.Date nowc = new java.util.Date();
pid = formatter.format(nowc);
BufferedWriter pidout = new BufferedWriter(new
FileWriter(logFileString + "pid"));
pidout.write(pid);
pidout.close();
log.println("Starting ConnectionPool:");
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("-----------------------------------------");
// 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){
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
log.println("\r\nAll attempts at connecting to Database exhausted");
throw new IOException();
}
}
catch (Exception e) {
e.printStackTrace();
throw new IOException();
}
// Fire up the background housekeeping thread
runner = new Thread(this);
runner.start();
} //End ConnectionPool()
/**
* 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;
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) {
log.println("Warnings on connection " +
String.valueOf(i) + " " + currSQLWarning);
connPool[i].clearWarnings();
}
}
catch(SQLException e) {
log.println("Cannot access Warnings: " + e);
}
}
for(int i=0; i < currConnections; i++) { // Do for each connection
long age = System.currentTimeMillis() - connCreateDate[i];
synchronized(connStatus) {
if(connStatus[i] > 0) { // In use, catch it next time!
continue;
}
connStatus[i] = 2; // Take offline (2 indicates housekeeping lock)
}
try { // Test the connection with createStatement call
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) {
try {
log.println(new Date().toString() +
" ***** Recycling connection " +
String.valueOf(i) + ":"
);
connPool[i].close();
createConn(i);
}
catch(SQLException e1) {
log.println("Failed: " + e1);
connStatus[i] = 0; // Can't open, try again next time
}
}
finally {
try {
if(stmt != null) {
stmt.close();
}
}
catch(SQLException e1){};
}
}
try {
Thread.sleep(20000);
} // Wait 20 seconds for next cycle
catch(InterruptedException e) {
// Returning from the run method sets the internal
// flag referenced by Thread.isAlive() to false.
// This is required because we don't use stop() to
// shutdown this thread.
return;
}
}
} // End run
/**
* This method hands out the connections in round-robin order.
* This prevents a faulty connection from locking
* up an application entirely. A browser 'refresh' will
* get the next connection while the faulty
* connection is cleaned up by the housekeeping thread.
*
* If the min number of threads are ever exhausted, new
* threads are added up the the max thread count.
* Finally, if all threads are in use, this method waits
* 2 seconds and tries again, up to ten times. After that, it
* returns a null.
*/
public Connection getConnection() {
Connection conn=null;
if(available){
boolean gotOne = false;
for(int outerloop=1; outerloop<=10; outerloop++) {
try {
int loop=0;
int roundRobin = connLast + 1;
if(roundRobin >= currConnections) roundRobin=0;
do {
synchronized(connStatus) {
if((connStatus[roundRobin] < 1) &&
(! connPool[roundRobin].isClosed()))
{
conn = connPool[roundRobin];
connStatus[roundRobin]=1;
connLockTime[roundRobin] =
System.currentTimeMillis();
connLast = roundRobin;
gotOne = true;
break;
}
else {
loop++;
roundRobin++;
if(roundRobin >= currConnections) roundRobin=0;
}
}
}
while((gotOne==false)&&(loop < currConnections));
}
catch (SQLException e1) {}
if(gotOne) {
break;
}
else {
synchronized(this) { // Add new connections to the pool
if(currConnections < maxConns) {
try {
createConn(currConnections);
currConnections++;
}
catch(SQLException e) {
log.println("Unable to create new connection: " + e);
}
}
}
try { Thread.sleep(2000); }
catch(InterruptedException e) {}
log.println("-----> Connections Exhausted! Will wait and try " +
"again in loop " +
String.valueOf(outerloop));
}
} // End of try 10 times loop
}
else {
log.println("Unsuccessful getConnection() request during destroy()");
} // End if(available)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -