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

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

一个连接池的例子 (一)

摘要: 一个连接池的例子 (一)
//文件: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

* dbDriver: JDBC driver. e.g. oracle.jdbc.driver.OracleDriver

* dbServer: JDBC connect string. e.g. jdbc:oracle:thin:@203.92.21.109:1526:orcl

* dbLogin: Database login name. e.g. Scott

* dbPassword: Database password. e.g. Tiger

* minConns: Minimum number of connections to start with.

* maxConns: Maximum number of connections in dynamic pool.

* logFileString: Absolute path name for log file. e.g. c:\temp\mylog.log

* maxConnTime: Time in days between connection resets. (Reset does a basic cleanup)

*/
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);

// Cant 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("Cant 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("Cant 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; // Cant 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 dont use stop() to
// shutdown this thread.
return;
}
}
} // End run


↑返回目录
前一篇: 一个连接池的例子 (二)
后一篇: JSP/Servlet构建三层管理信息系统