站内搜索: 请输入搜索关键词

当前页面: 开发资料首页JSP 专题一个连接池的例子 (二)

一个连接池的例子 (二)

摘要: 一个连接池的例子 (二)

/**
* 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:
*

    *
  1. getConnection() will refuse to return connections.
    *
  2. The housekeeping thread is shut down.

    * Up to the time of millis milliseconds after shutdown of
    * the housekeeping thread, freeConnection() can still be
    * called to return used connections.
    *
  3. After millis milliseconds after the shutdown of the
    * housekeeping thread, all connections in the pool are closed.
    *
  4. If any connections were in use while being closed then a
    * SQLException is thrown.
    *
  5. The log is closed.
    *


* Call this method from a servlet destroy() method.
*
* @param millis the time to wait in milliseconds.
* @exception SQLException if connections were in use after
* millis.
*/
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 destroy() method
* with a millis
* value of 10000 (10 seconds) and ignores SQLException
* 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, Ill 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 should
* not
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();
}
}


}

↑返回目录
前一篇: jsp+beans实现读取数据库的例子
后一篇: 一个连接池的例子 (一)