作者:sonymusic
email: sonymusic@china.com
//文件: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: empmylog.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(" All 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
/**
* 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)
return conn;
}
/**
* Returns the local JDBC ID for a connection.
*/
public int idOfConnection(Connection conn) {
int match;
String tag;
try {
tag = conn.toString();
}
catch (NullPointerException e1) {
tag = "none";
}
match=-1;
for(int i=0; i< currConnections; i++) {
if(connID[i].equals(tag)) {
match = i;
break;
}
}
return match;
}
/**
* Frees a connection. Replaces connection back into the main pool for
* reuse.
*/
public String freeConnection(Connection conn) {
String res="";
int thisconn = idOfConnection(conn);
if(thisconn >= 0) {
connStatus[thisconn]=0;
res = "freed " + conn.toString();
//log.println("Freed connection " + String.valueOf(thisconn) +
// " normal exit: ");
}
else {
log.println("----> Could not free connection!!!");
}
return res;
}
//文件:DbConnectionDefaultPool.java的第三部分
/**
* Returns the age of a connection -- the time since it was handed out to
* an application.
*/
public long getAge(Connection conn) { // Returns the age of the connection in millisec.
int thisconn = idOfConnection(conn);
return System.currentTimeMillis() - connLockTime[thisconn];
}
private void createConn(int i) throws SQLException {
Date now = new Date();
try {
Class.forName (dbDriver);
Properties dbProp = new Properties();
//log.println("Creating.....");
dbProp.put("user", dbLogin);
dbProp.put("password", dbPassword);
dbProp.put("characterEncoding","gb2112");
//dbProp.put("useUnicode", "true");
connPool[i] = DriverManager.getConnection
(dbServer,dbProp);
//log.println("Created Ok...");
connStatus[i]=0;
connID[i]=connPool[i].toString();
connLockTime[i]=0;
connCreateDate[i] = now.getTime();
}
catch (ClassNotFoundException e2) {}
log.println(now.toString() + " Opening connection " + String.valueOf(i) +
" " + connPool[i].toString() + ":");
}
/**
* Shuts down the housekeeping thread and closes all connections
* in the pool. Call this method from the destroy() method of the servlet.
*/
/**
* Multi-phase shutdown. having following sequence:
* <OL>
* <LI><code>getConnection()</code> will refuse to return connections.
* <LI>The housekeeping thread is shut down.<br>
* Up to the time of <code>millis</code> milliseconds after shutdown of
* the housekeeping thread, <code>freeConnection()</code> can still be
* called to return used connections.
* <LI>After <code>millis</code> milliseconds after the shutdown of the
* housekeeping thread, all connections in the pool are closed.
* <LI>If any connections were in use while being closed then a
* <code>SQLException</code> is thrown.
* <LI>The log is closed.
* </OL><br>
* Call this method from a servlet destroy() method.
*
* @param millis the time to wait in milliseconds.
* @exception SQLException if connections were in use after
* <code>millis</code>.
*/
public void destroy(int millis) throws SQLException {
// Checking for invalid negative arguments is not necessary,
// Thread.join() does this already in runner.join().
// Stop issuing connections
available=false;
// Shut down the background housekeeping thread
runner.interrupt();
// Wait until the housekeeping thread has died.
try { runner.join(millis); }
catch(InterruptedException e){} // ignore
// The housekeeping thread could still be running
// (e.g. if millis is too small). This case is ignored.
// At worst, this method will throw an exception with the
// clear indication that the timeout was too short.
long startTime=System.currentTimeMillis();
// Wait for freeConnection() to return any connections
// that are still used at this time.
int useCount;
while((useCount=getUseCount())>0 && System.currentTimeMillis() - startTime <= millis) {
try { Thread.sleep(500); }
catch(InterruptedException e) {} // ignore
}
// Close all connections, whether safe or not
for(int i=0; i < currConnections; i++) {
try {
connPool[i].close();
}
catch (SQLException e1)
{
log.println("Cannot close connections on Destroy");
}
}
if(useCount > 0) {
//BT-test successful
String msg="Unsafe shutdown: Had to close "+useCount+
" active DB connections after "+millis+"ms";
log.println(msg);
// Close all open files
log.close();
// Throwing following Exception is essential because servlet authors
// are likely to have their own error logging requirements.
throw new SQLException(msg);
}
// Close all open files
log.close();
}//End destroy()
/**
* Less safe shutdown. Uses default timeout value.
* This method simply calls the <code>destroy()</code> method
* with a <code>millis</code>
* value of 10000 (10 seconds) and ignores <code>SQLException</code>
* thrown by that method.
* @see #destroy(int)
*/
public void destroy() {
try {
destroy(10000);
}
catch(SQLException e) {}
}
/**
* Returns the number of connections in use.
*/
// This method could be reduced to return a counter that is
// maintained by all methods that update connStatus.
// However, it is more efficient to do it this way because:
// Updating the counter would put an additional burden on the most
// frequently used methods; in comparison, this method is
// rarely used (although essential).
public int getUseCount() {
int useCount=0;
synchronized(connStatus) {
for(int i=0; i < currConnections; i++) {
if(connStatus[i] > 0) { // In use
useCount++;
}
}
}
return useCount;
}//End getUseCount()
/**
* Returns the number of connections in the dynamic pool.
*/
public int getSize() {
return currConnections;
}//End getSize()
}
/**
* An implementation of the Connection interface that wraps an underlying
* Connection object. It releases the connection back to a connection pool
* when Connection.close() is called.
*/
public class ConnectionWrapper implements Connection {
private Connection connection;
private ConnectionPool connectionPool;
public ConnectionWrapper(Connection connection, ConnectionPool connectionPool) {
this.connection = connection;
this.connectionPool = connectionPool;
}
/**
* Instead of closing the underlying connection, we simply release
* it back into the pool.
*/
public void close() throws SQLException {
connectionPool.freeConnection(this.connection);
//Release object references. Any further method calls on the
//connection will fail.
connection = null;
connectionPool = null;
}
public Statement createStatement() throws SQLException {
return connection.createStatement();
}
public PreparedStatement prepareStatement(String sql) throws SQLException {
return connection.prepareStatement(sql);
}
public CallableStatement prepareCall(String sql) throws SQLException {
return connection.prepareCall(sql);
}
public String nativeSQL(String sql) throws SQLException {
return connection.nativeSQL(sql);
}
public void setAutoCommit(boolean autoCommit) throws SQLException {
connection.setAutoCommit(autoCommit);
}
public boolean getAutoCommit() throws SQLException {
return connection.getAutoCommit();
}
public void commit() throws SQLException {
connection.commit();
}
public void rollback() throws SQLException {
connection.rollback();
}
public boolean isClosed() throws SQLException {
return connection.isClosed();
}
public DatabaseMetaData getMetaData() throws SQLException {
return connection.getMetaData();
}
public void setReadOnly(boolean readOnly) throws SQLException {
connection.setReadOnly(readOnly);
}
public boolean isReadOnly() throws SQLException {
return connection.isReadOnly();
}
public void setCatalog(String catalog) throws SQLException {
connection.setCatalog(catalog);
}
public String getCatalog() throws SQLException {
return connection.getCatalog();
}
public void setTransactionIsolation(int level) throws SQLException {
connection.setTransactionIsolation(level);
}
public int getTransactionIsolation() throws SQLException {
return connection.getTransactionIsolation();
}
public SQLWarning getWarnings() throws SQLException {
return connection.getWarnings();
}
public void clearWarnings() throws SQLException {
connection.clearWarnings();
}
public Statement createStatement(int resultSetType, int resultSetConcurrency)
throws SQLException
{
return connection.createStatement(resultSetType, resultSetConcurrency);
}
public PreparedStatement prepareStatement(String sql, int resultSetType,
int resultSetConcurrency) throws SQLException
{
return connection.prepareStatement(sql, resultSetType, resultSetConcurrency);
}
public CallableStatement prepareCall(String sql, int resultSetType,
int resultSetConcurrency) throws SQLException
{
return prepareCall(sql, resultSetType, resultSetConcurrency);
}
public Map getTypeMap() throws SQLException {
return connection.getTypeMap();
}
public void setTypeMap(Map map) throws SQLException {
connection.setTypeMap(map);
}
}
}
//文件:DbConnectionManager.java
package com.qingtuo.db.pool;
import java.sql.*;
import java.io.*;
import java.util.*;
/**
* Central manager of database connections.
*/
public class DbConnectionManager {
private static DbConnectionProvider connectionProvider;
private static Object providerLock = new Object();
/**
* Returns a database connection from the currently active connection
* provider.
*/
public static Connection getConnection() {
if (connectionProvider == null) {
synchronized (providerLock) {
if (connectionProvider == null) {
//Create the connection provider -- for now, this is hardcoded. For
//the next beta, I′ll change this to load up the provider dynamically.
connectionProvider = new DbConnectionDefaultPool();
connectionProvider.start();
}
}
}
Connection con = connectionProvider.getConnection();
if (con == null) {
System.err.println("WARNING: DbConnectionManager.getConnection() failed to obtain a connection.");
}
return con;
}
/**
* Returns the current connection provider. The only case in which this
* method should be called is if more information about the current
* connection provider is needed. Database connections should always be
* obtained by calling the getConnection method of this class.
*/
public static DbConnectionProvider getDbConnectionProvider() {
return connectionProvider;
}
/**
* Sets the connection provider. The old provider (if it exists) is shut
* down before the new one is started. A connection provider <b>should
* not</b> be started before being passed to the connection manager.
*/
public static void setDbConnectionProvider(DbConnectionProvider provider) {
synchronized (providerLock) {
if (connectionProvider != null) {
connectionProvider.destroy();
connectionProvider = null;
}
connectionProvider = provider;
provider.start();
}
}
}
//文件:DbConnectionProvider.java
package com.qingtuo.db.pool;
import java.sql.*;
import java.util.*;
public abstract class DbConnectionProvider {
/** Dummy values. Override in subclasses. **/
private static final String NAME = "";
private static final String DESCRIPTION = "";
private static final String AUTHOR = "";
private static final int MAJOR_VERSION = 0;
private static final int MINOR_VERSION = 0;
private static final boolean POOLED = false;
/**
* Returns the name of the connection provider.
*/
public String getName() {
return NAME;
}
/**
* Returns a description of the connection provider.
*/
public String getDescription() {
return DESCRIPTION;
}
/**
* Returns the author of the connection provider.
*/
public String getAuthor() {
return AUTHOR;
}
/**
* Returns the major version of the connection provider, i.e. the 1 in 1.0.
*/
public int getMajorVersion() {
return MAJOR_VERSION;
}
public int getMinorVersion() {
return MINOR_VERSION;
}
/**
* Returns true if this connection provider provides connections out
* of a connection pool.
*/
public boolean isPooled() {
return POOLED;
}
/**
* Returns a database connection. When a Jive component is done with a
* connection, it will call the close method of that connection. Therefore,
* connection pools with special release methods are not directly
* supported by the connection provider infrastructure. Instead, connections
* from those pools should be wrapped such that calling the close method
* on the wrapper class will release the connection from the pool.
*/
public abstract Connection getConnection();
/**
* Starts the connection provider. For some connection providers, this
* will be a no-op. However, connection provider users should always call
* this method to make sure the connection provider is started.
*/
protected abstract void start();
/**
* This method should be called whenever properties have been changed so
* that the changes will take effect.
*/
protected abstract void restart();
/**
* Tells the connection provider to destroy itself. For many connection
* providers, this will essentially result in a no-op. However,
* connection provider users should always call this method when changing
* from one connection provider to another to ensure that there are no
* dangling database connections.
*/
protected abstract void destroy();
/**
* Returns the value of a property of the connection provider.
*
* @param name the name of the property.
* @returns the value of the property.
*/
public abstract String getProperty(String 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 abstract String getPropertyDescription(String name);
/**
* Returns an enumeration of the property names for the connection provider.
*/
public abstract Enumeration 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 abstract void setProperty(String name, String value);
}
//文件:PropertyManager.java
//这个类其实没什么用了,可以去掉,但需要去掉前面几个类中对这个类的引用。
package com.qingtuo.db.pool;
import java.util.*;
import java.io.*;
/**
* Manages properties for the entire Jive system. Properties are merely
* pieces of information that need to be saved in between server restarts.
* <p>
* At the moment, properties are stored in a Java Properties file. In a version
* of Jive coming soon, the properties file format will move to XML. XML
* properties will allow hierarchical property structures which may mean the
* API of this class will have to change.
* <p>
* Jive properties are only meant to be set and retrevied by core Jive classes.
* Therefore, SKIN writers should probably ignore this class.
* <p>
* This class is implemented as a singleton since many classloaders seem to
* take issue with doing classpath resource loading from a static context.
*/
public class PropertyManager {
private static PropertyManager manager = null;
private static Object managerLock = new Object();
private static String propsName = "/pcc_2000.properties";
/**
* Returns a Jive property
*
* @param name the name of the property to return.
* @returns the property value specified by name.
*/
public static String getProperty(String name) {
if (manager == null) {
synchronized(managerLock) {
if (manager == null) {
String sysname=System.getProperty("os.name").toUpperCase();
if(sysname.indexOf("WIN")!=-1){
propsName=propsName2000;
}
else{
propsName=propsNameLinux;
}
manager = new PropertyManager(propsName);
}
}
}
return manager.getProp(name);
}
/**
* Sets a Jive property.
*
* @param name the name of the property being set.
* @param value the value of the property being set.
*/
public static void setProperty(String name, String value) {
if (manager == null) {
synchronized(managerLock) {
if (manager == null) {
manager = new PropertyManager(propsName);
}
}
}
manager.setProp(name, value);
}
/**
* Returns true if the properties are readable. This method is mainly
* valuable at setup time to ensure that the properties file is setup
* correctly.
*/
public static boolean propertyFileIsReadable() {
if (manager == null) {
synchronized(managerLock) {
if (manager == null) {
manager = new PropertyManager(propsName);
}
}
}
return manager.propFileIsReadable();
}
/**
* Returns true if the properties are writable. This method is mainly
* valuable at setup time to ensure that the properties file is setup
* correctly.
*/
public static boolean propertyFileIsWritable() {
if (manager == null) {
synchronized(managerLock) {
if (manager == null) {
manager = new PropertyManager(propsName);
}
}
}
return manager.propFileIsWritable();
}
/**
* Returns true if the jive.properties file exists where the path property
* purports that it does.
*/
public static boolean propertyFileExists() {
if (manager == null) {
synchronized(managerLock) {
if (manager == null) {
manager = new PropertyManager(propsName);
}
}
}
return manager.propFileExists();
}
private Properties properties = null;
private Object propertiesLock = new Object();
private String resourceURI;
/**
* Singleton access only.
*/
private PropertyManager(String resourceURI) {
this.resourceURI = resourceURI;
}
/**
* Gets a Jive property. Jive properties are stored in jive.properties.
* The properties file should be accesible from the classpath. Additionally,
* it should have a path field that gives the full path to where the
* file is located. Getting properties is a fast operation.
*/
public String getProp(String name) {
//If properties aren′t loaded yet. We also need to make this thread
//safe, so synchronize...
if (properties == null) {
synchronized(propertiesLock) {
//Need an additional check
if (properties == null) {
loadProps();
}
}
}
return properties.getProperty(name);
}
/**
* Sets a Jive property. Because the properties must be saved to disk
* every time a property is set, property setting is relatively slow.
*/
public void setProp(String name, String value) {
//Only one thread should be writing to the file system at once.
synchronized (propertiesLock) {
//Create the properties object if necessary.
if (properties == null) {
loadProps();
}
properties.setProperty(name, value);
//Now, save the properties to disk. In order for this to work, the user
//needs to have set the path field in the properties file. Trim
//the String to make sure there are no extra spaces.
String path = properties.getProperty("path").trim();
OutputStream out = null;
try {
out = new FileOutputStream(path);
properties.store(out, "jive.properties -- " + (new java.util.Date()));
}
catch (Exception ioe) {
System.err.println("There was an error writing jive.properties to " + path + ". " +
"Ensure that the path exists and that the Jive process has permission " +
"to write to it -- " + ioe);
ioe.printStackTrace();
}
finally {
try {
out.close();
} catch (Exception e) { }
}
}
}
/**
* Loads Jive properties from the disk.
*/
private void loadProps() {
properties = new Properties();
InputStream in = null;
try {
in = getClass().getResourceAsStream(resourceURI);
properties.load(in);
}
catch (IOException ioe) {
System.err.println("Error reading Pcc properties" + ioe);
ioe.printStackTrace();
}
finally {
try {
in.close();
} catch (Exception e) { }
}
}
/**
* Returns true if the properties are readable. This method is mainly
* valuable at setup time to ensure that the properties file is setup
* correctly.
*/
public boolean propFileIsReadable() {
try {
InputStream in = getClass().getResourceAsStream(resourceURI);
return true;
}
catch (Exception e) {
return false;
}
}
/**
* Returns true if the jive.properties file exists where the path property
* purports that it does.
*/
public boolean propFileExists() {
String path = getProp("path");
File file = new File(path);
if (file.isFile()) {
return true;
}
else {
return false;
}
}
/**
* Returns true if the properties are writable. This method is mainly
* valuable at setup time to ensure that the properties file is setup
* correctly.
*/
public boolean propFileIsWritable() {
String path = getProp("path");
File file = new File(path);
if (file.isFile()) {
//See if we can write to the file
if (file.canWrite()) {
return true;
}
else {
return false;
}
}
else {
return false;
}
}
private static String propsName2000 = "/pcc_2000.properties";
private static String propsNameLinux = "/pcc_linux.properties";
}
这个连接池是直接从JIVE中取出来的,进行了一下修改,使得连接参数直接在程序中设定而不是从属性文件中读取。
用法:
先设定自己的连接参数,在DbConnectionDefaultPool.java文件的loadProperties方法中。注重你也需要设定连接池的log文件的存放位置。
String driver="org.gjt.mm.mysql.Driver";//这是使用的JDBC驱动
String server="jdbc:mysql://192.100.100.1/qingtuo";//使用的URL
//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";//定时清除无用连接间隔(以天为单位)
然后
在你的程序中只需要将这个包com.qingtuo.db.pool import进来,再向下面这样用就行了。
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs=null;
try {
con = DbConnectionManager.getConnection();
//这里写你的SQL语句
}
catch (SQLException sqle) {
throw sqle;
}
finally {
try {
pstmt.close();
}
catch (Exception e) {
e.printStackTrace();
}
try {
con.close();
}
catch (Exception e) {
e.printStackTrace();
}
}
优点
虽然很多应用服务器也有连接池,但这样做的好处是,更加通用一些。