//文件:dbconnectiondefaultpool.java的第一部分
//请注意看里面注明的一处需要修改连接参数的地方
package com.qingtuo.db.pool;
import java.sql.*;
import java.util.*;
import java.io.*;
import java.text.*;
import java.util.date;
/**
* default jive connection provider. it uses the excellent connection pool
* available from http://www.javaexchange.com. this connection provider is a
* a good choice unless you can use a container-managed one.
*/
public class dbconnectiondefaultpool extends dbconnectionprovider {
private static final string name = "default connection pool";
private static final string description = "the default connection provider "
+ "that uses the connection pool from javaexchange.com. it works with "
+ "almost any database setup, is customizable, and offers good performance. "
+ "use this connection provider unless you have your own or can use a "
+ "container managed connection pool.";
private static final string author = "coolservlets.com";
private static final int major_version = 1;
private static final int minor_version = 0;
private static final boolean pooled = true;
private connectionpool connectionpool = null;
private properties props;
private properties propdescriptions;
private object initlock = new object();
public dbconnectiondefaultpool() {
//this.manager = manager;
props = new properties();
propdescriptions = new properties();
//initialize all property values
initializeproperties();
//load any existing property values
loadproperties();
}
/**
* returns a database connection.
*/
public connection getconnection() {
if (connectionpool == null) {
//block until the init has been done
synchronized(initlock) {
//if still null, something has gone wrong
if (connectionpool == null) {
system.err.println("warning: dbconnectiondefaultpool.getconnection() was " +
"called when the internal pool has not been initialized.");
return null;
}
}
}
return new connectionwrapper(connectionpool.getconnection(), connectionpool);
}
/**
* starts the pool.
*/
protected void start() {
//acquire lock so that no connections can be returned.
synchronized (initlock) {
//get properties
string driver = props.getproperty("driver");
string server = props.getproperty("server");
string username = props.getproperty("username");
string password = props.getproperty("password");
int minconnections = 0, maxconnections = 0;
double connectiontimeout = 0.0;
try {
minconnections = integer.parseint(props.getproperty("minconnections"));
maxconnections = integer.parseint(props.getproperty("maxconnections"));
connectiontimeout = double.parsedouble(props.getproperty("connectiontimeout"));
}
catch (exception e) {
system.err.println("error: could not parse default pool properties. " +
"make sure the values exist and are correct.");
e.printstacktrace();
return;
}
string logpath = props.getproperty("logpath");
try {
connectionpool = new connectionpool(driver, server, username, password,
minconnections, maxconnections, logpath, connectiontimeout);
}
catch (ioexception ioe) {
system.err.println("error starting dbconnectiondefaultpool: " + ioe);
ioe.printstacktrace();
}
}
}
/**
* restarts the pool to take into account any property changes.
*/
protected void restart() {
//kill off pool.
destroy();
//reload properties.
loadproperties();
//start a new pool.
start();
}
/**
* destroys the connection pool.
*/
protected void destroy() {
if (connectionpool != null) {
try {
connectionpool.destroy(1);
}
catch (exception e) {
e.printstacktrace();
}
}
//release reference to connectionpool
connectionpool = null;
}
/**
* returns the value of a property of the connection provider.
*
* @param name the name of the property.
* @returns the value of the property.
*/
public string getproperty(string name) {
return (string)props.get(name);
}
/**
* returns the description of a property of the connection provider.
*
* @param name the name of the property.
* @return the description of the property.
*/
public string getpropertydescription(string name) {
return (string)propdescriptions.get(name);
}
/**
* returns an enumeration of the property names for the connection provider.
*/
public enumeration propertynames() {
return props.propertynames();
}
/**
* sets a property of the connection provider. each provider has a set number
* of properties that are determined by the author. trying to set a non-
* existant property will result in an illegalargumentexception.
*
* @param name the name of the property to set.
* @param value the new value for the property.
*
*/
public void setproperty(string name, string value) {
props.put(name, value);
saveproperties();
}
/**
* give default values to all the properties and descriptions.
*/
private void initializeproperties() {
props.put("driver","");
props.put("server","");
props.put("username","");
props.put("password","");
props.put("minconnections","");
props.put("maxconnections","");
props.put("logpath","");
props.put("connectiontimeout","");
propdescriptions.put("driver","jdbc driver. e.g. 'oracle.jdbc.driver.oracledriver'");
propdescriptions.put("server","jdbc connect string. e.g. 'jdbc:oracle:thin:@203.92.21.109:1526:orcl'");
propdescriptions.put("username","database username. e.g. 'scott'");
propdescriptions.put("password","database password. e.g. 'tiger'");
propdescriptions.put("minconnections","minimum # of connections to start with in pool. three is the recommended minimum");
propdescriptions.put("maxconnections","maximum # of connections in dynamic pool. fifteen should give good performance for an average load.");
propdescriptions.put("logpath","absolute path name for log file. e.g. 'c:\\logs\\jivedblog.log'");
propdescriptions.put("connectiontimeout","time in days between connection resets. e.g. '.5'");
}
/**
* load whatever properties that already exist.
*/
private void loadproperties() {
//在这里修改一些连接参数
//in 2000
/*
string driver="org.gjt.mm.mysql.driver";
string server="jdbc:mysql://192.100.100.11/pcc";
string username="pcc";
string password="pcc123";
string minconnections="3";
string maxconnections="10";
string logpath="c:\\temp\\qingtuodblog.log";
string connectiontimeout="0.5";
*/
//in linux
string driver="org.gjt.mm.mysql.driver";
string server="jdbc:mysql://192.100.100.1/qingtuo";
//string server="jdbc:mysql://192.168.0.1/qingtuo";
string username="qingtuo";
string password="qingtuo";
string minconnections="3";
string maxconnections="20";
string logpath="c:\\temp\\qingtuodblog.log";
// string logpath="/tmp/qingtuodblog.log";
string connectiontimeout="0.5";
if (driver != null) { props.setproperty("driver", driver); }
if (server != null) { props.setproperty("server", server); }
if (username != null) { props.setproperty("username", username); }
if (password != null) { props.setproperty("password", password); }
//if (database != null) { props.setproperty("database", database); }
if (minconnections != null) { props.setproperty("minconnections", minconnections); }
if (maxconnections != null) { props.setproperty("maxconnections", maxconnections); }
if (logpath != null) { props.setproperty("logpath", logpath); }
if (connectiontimeout != null) { props.setproperty("connectiontimeout", connectiontimeout); }
}
private void saveproperties() {
propertymanager.setproperty("dbconnectiondefaultpool.driver", props.getproperty("driver"));
propertymanager.setproperty("dbconnectiondefaultpool.server", props.getproperty("server"));
propertymanager.setproperty("dbconnectiondefaultpool.username", props.getproperty("username"));
propertymanager.setproperty("dbconnectiondefaultpool.password", props.getproperty("password"));
propertymanager.setproperty("dbconnectiondefaultpool.minconnections", props.getproperty("minconnections"));
propertymanager.setproperty("dbconnectiondefaultpool.maxconnections", props.getproperty("maxconnections"));
propertymanager.setproperty("dbconnectiondefaultpool.logpath", props.getproperty("logpath"));
propertymanager.setproperty("dbconnectiondefaultpool.connectiontimeout", props.getproperty("connectiontimeout"));
}
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++) {
log.println("create conn "+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) {
throw new ioexception();
}
// fire up the background housekeeping thread
runner = new thread(this);
runner.start();
} //end connectionpool()
//文件:dbconnectiondefaultpool.java的第二部分
/**
* 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