⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 connectionpool.java

📁 DBPool,一个很好的数据库连接池的源代码
💻 JAVA
字号:
/*
	DBPool - JDBC Connection Pool Manager
	Copyright (c) Giles Winstanley
*/
package snaq.db;

import snaq.util.*;
import java.sql.*;
import java.util.*;

/**
 * Implementation of a database connection pool.
 * @see snaq.db.CacheConnection
 * @see snaq.db.CachedCallableStatement
 * @see snaq.db.CachedPreparedStatement
 * @author Giles Winstanley
 */
public class ConnectionPool extends ObjectPool implements Comparable
{
	private String url, user, pass;
	private Properties props;
	private ConnectionValidator validator = new DefaultValidator();
	private PasswordDecoder decoder;
	private boolean cacheSS, cachePS, cacheCS;
	private List listeners = new ArrayList();


	/**
	 * Creates new connection pool.
	 * @param name pool name
	 * @param poolSize maximum number of pooled objects, or 0 for no limit
	 * @param maxSize maximum number of possible objects, or 0 for no limit
	 * @param expiryTime expiry time (milliseconds) for pooled object, or 0 for no expiry
	 * @param url JDBC connection URL
	 * @param username database username
	 * @param password password for the database username supplied
	 */
	public ConnectionPool(String name, int poolSize, int maxSize, long expiryTime, String url, String username, String password)
	{
		super(name, poolSize, maxSize, expiryTime);
		this.url = url;
		this.user = username;
		this.pass = password;
		this.props = null;
		setCaching(true);
		addObjectPoolListener(new EventRelay());
	}

	/**
	 * Creates new connection pool.
	 * @param name pool name
	 * @param poolSize maximum number of pooled objects, or 0 for no limit
	 * @param maxSize maximum number of possible objects, or 0 for no limit
	 * @param expiryTime expiry time (milliseconds) for pooled object, or 0 for no expiry
	 * @param url JDBC connection URL
	 * @param props connection properties
	 */
	public ConnectionPool(String name, int poolSize, int maxSize, long expiryTime, String url, Properties props)
	{
		this(name, poolSize, maxSize, expiryTime, url, null, null);
		this.props = props;
		this.pass = props.getProperty("password");
		addObjectPoolListener(new EventRelay());
	}


	/**
	 * Creates a new database connection.
	 */
	protected Reusable create() throws SQLException
	{
		Connection con = null;
		CacheConnection ccon = null;
		try
		{
			if (props != null)
			{
				if (decoder != null)
					props.setProperty("password", new String(decoder.decode(pass)));
				log("Getting connection (properties): " + url);
				con = DriverManager.getConnection(url, props);
			}
			else if (user != null)
			{
				try
				{
					if (decoder != null)
					{
						log("Getting connection (user/enc.pass): " + url);
						con = DriverManager.getConnection(url, user, new String(decoder.decode(pass)));
					}
					else
					{
						log("Getting connection (user/pass): " + url);
						con = DriverManager.getConnection(url, user, pass);
					}
				}
				catch (SQLException sqle)
				{
					log("Failed to connect with standard authentication...trying with just JDBC URL");
					log("Getting connection (URL only): " + url);
					con = DriverManager.getConnection(url);
				}
			}
			else
				con = DriverManager.getConnection(url);

			// Add caching wrapper to connection
			ccon = new CacheConnection(this, con);
			ccon.setCacheStatements(cacheSS);
			ccon.setCachePreparedStatements(cachePS);
			ccon.setCacheCallableStatements(cacheCS);
			log("Created a new connection");

			// Check for warnings
			SQLWarning warn = con.getWarnings();
			while (warn != null)
			{
				log("Warning - " + warn.getMessage());
				warn = warn.getNextWarning();
			}
		}
		catch (SQLException sqle)
		{
			log(sqle, "Can't create a new connection for " + url);
			// Clean up open connection.
			try { con.close(); }
			catch (SQLException sqle2) {}
			// Rethrow exception.
			throw sqle;
		}
		return ccon;
	}

	/**
	 * Validates a connection.
	 */
	protected boolean isValid(final Reusable o)
	{
		if (o == null)
			return false;
		if (validator == null)
			return true;

		try
		{
			boolean valid = validator.isValid((Connection)o);
			if (!valid)
				fireValidationErrorEvent();
			return valid;
		}
		catch (Exception e) { log(e, "Exception during validation"); return false; }
	}

	/**
	 * Sets the validator class for connections.
	 */
	public void setValidator(ConnectionValidator cv) { validator = cv; }

	/**
	 * Returns the current validator class.
	 */
	public ConnectionValidator getValidator() { return validator; }

	/**
	 * Sets the password decoder class.
	 */
	public void setPasswordDecoder(PasswordDecoder pd) { decoder = pd; }

	/**
	 * Returns the current password decoder class.
	 */
	public PasswordDecoder getPasswordDecoder() { return decoder; }

	/**
	 * Closes the given connection.
	 */
	protected void destroy(final Reusable o)
	{
		if (o == null)
			return;
		try
		{
			((CacheConnection)o).release();
			log("Destroyed connection");
		}
		catch (SQLException e)
		{
			log(e, "Can't destroy connection");
		}
	}

	/**
	 * Gets a connection from the pool.
	 */
	public Connection getConnection() throws SQLException
	{
		try
		{
			Reusable o = super.checkOut();
			if (o != null)
			{
				CacheConnection cc = (CacheConnection)o;
				cc.setOpen();
				return cc;
			}
			return null;
		}
		catch (Exception e)
		{
			log(e, "Error getting connection");
			if (e instanceof SQLException)
				throw (SQLException)e;
			else
			{
				Throwable t = e.getCause();
				while (t != null)
				{
					log(e, "Error getting connection");
					t = t.getCause();
				}
				throw new SQLException(e.getMessage());
			}
		}
	}

	/**
	 * Gets a connection from the pool.
	 */
	public Connection getConnection(long timeout) throws SQLException
	{
		try
		{
			Object o = super.checkOut(timeout);
			if (o != null)
			{
				CacheConnection cc = (CacheConnection)o;
				cc.setOpen();
				return cc;
			}
			return null;
		}
		catch (Exception e)
		{
			if (e instanceof SQLException)
				throw (SQLException)e;
			else
			{
				log(e, "Error getting connection");
				throw new SQLException(e.getMessage());
			}
		}
	}

	/**
	 * Returns a connection to the pool (for internal use only).
	 * Connections obtained from the pool should be returned by calling the
	 * close() method on the connection.
	 */
	protected void freeConnection(Connection c) throws SQLException
	{
		if (c == null  ||  !CacheConnection.class.isInstance(c))
			log("Attempt to return invalid item");
		else
		{
			CacheConnection cc = (CacheConnection)c;
			super.checkIn((Reusable)c);
		}
	}

	/**
	 * Determines whether to perform statement caching.
	 * This applies to all types of statements (normal, prepared, callable).
	 */
	public void setCaching(boolean b)
	{
		cacheSS = cachePS = cacheCS = b;
	}

	/**
	 * Determines whether to perform statement caching.
	 * @param ss whether to cache Statement objects
	 * @param ps whether to cache PreparedStatement objects
	 * @param cs whether to cache CallableStatement objects
	 */
	public void setCaching(boolean ss, boolean ps, boolean cs)
	{
		cacheSS = ss;
		cachePS = ps;
		cacheCS = cs;
	}

	/** Returns a descriptive string for this pool instance. */
	public String toString() { return getName(); }
	/** Compares this instances to other instances by name. */
	public int compareTo(Object o) { return this.toString().compareTo(((ConnectionPool)o).toString()); }

	//**************************
	//  Event-handling methods
	//**************************

	/**
	 * Adds an ConnectionPoolListener to the event notification list.
	 */
	public final void addConnectionPoolListener(ConnectionPoolListener x)
	{
		listeners.add(x);
	}

	/**
	 * Removes an ConnectionPoolListener from the event notification list.
	 */
	public final void removeConnectionPoolListener(ConnectionPoolListener x)
	{
		listeners.remove(x);
	}

	private final void fireValidationErrorEvent()
	{
		if (listeners.isEmpty())
			return;
		ConnectionPoolEvent poolEvent = new ConnectionPoolEvent(this, ConnectionPoolEvent.VALIDATION_ERROR);
		for (Iterator iter = listeners.iterator(); iter.hasNext();)
			((ConnectionPoolListener)iter.next()).validationError(poolEvent);
	}

	private final void firePoolCheckOutEvent()
	{
		if (listeners.isEmpty())
			return;
		ConnectionPoolEvent poolEvent = new ConnectionPoolEvent(this, ConnectionPoolEvent.CHECKOUT);
		for (Iterator iter = listeners.iterator(); iter.hasNext();)
			((ConnectionPoolListener)iter.next()).poolCheckOut(poolEvent);
	}

	private final void firePoolCheckInEvent()
	{
		if (listeners.isEmpty())
			return;
		ConnectionPoolEvent poolEvent = new ConnectionPoolEvent(this, ConnectionPoolEvent.CHECKIN);
		for (Iterator iter = listeners.iterator(); iter.hasNext();)
			((ConnectionPoolListener)iter.next()).poolCheckIn(poolEvent);
	}

	private final void fireMaxPoolLimitReachedEvent()
	{
		if (listeners.isEmpty())
			return;
		ConnectionPoolEvent poolEvent = new ConnectionPoolEvent(this, ConnectionPoolEvent.MAX_POOL_LIMIT_REACHED);
		for (Iterator iter = listeners.iterator(); iter.hasNext();)
			((ConnectionPoolListener)iter.next()).maxPoolLimitReached(poolEvent);
	}

	private final void fireMaxPoolLimitExceededEvent()
	{
		if (listeners.isEmpty())
			return;
		ConnectionPoolEvent poolEvent = new ConnectionPoolEvent(this, ConnectionPoolEvent.MAX_POOL_LIMIT_EXCEEDED);
		for (Iterator iter = listeners.iterator(); iter.hasNext();)
			((ConnectionPoolListener)iter.next()).maxPoolLimitExceeded(poolEvent);
	}

	private final void fireMaxSizeLimitReachedEvent()
	{
		if (listeners.isEmpty())
			return;
		ConnectionPoolEvent poolEvent = new ConnectionPoolEvent(this, ConnectionPoolEvent.MAX_SIZE_LIMIT_REACHED);
		for (Iterator iter = listeners.iterator(); iter.hasNext();)
			((ConnectionPoolListener)iter.next()).maxSizeLimitReached(poolEvent);
	}

	private final void fireMaxSizeLimitErrorEvent()
	{
		if (listeners.isEmpty())
			return;
		ConnectionPoolEvent poolEvent = new ConnectionPoolEvent(this, ConnectionPoolEvent.MAX_SIZE_LIMIT_ERROR);
		for (Iterator iter = listeners.iterator(); iter.hasNext();)
			((ConnectionPoolListener)iter.next()).maxSizeLimitError(poolEvent);
	}

	private final void fireParametersChangedEvent()
	{
		if (listeners == null  ||  listeners.isEmpty())
			return;
		ConnectionPoolEvent poolEvent = new ConnectionPoolEvent(this, ConnectionPoolEvent.PARAMETERS_CHANGED);
		for (Iterator iter = listeners.iterator(); iter.hasNext();)
			((ConnectionPoolListener)iter.next()).poolParametersChanged(poolEvent);
	}

	private final void firePoolReleasedEvent()
	{
		if (listeners.isEmpty())
			return;
		ConnectionPoolEvent poolEvent = new ConnectionPoolEvent(this, ConnectionPoolEvent.POOL_RELEASED);
		for (Iterator iter = listeners.iterator(); iter.hasNext();)
			((ConnectionPoolListener)iter.next()).poolReleased(poolEvent);
	}


	/**
	 * Class to relay ObjectPoolEvents as ConnectionPoolEvents for convenience.
	 */
	private final class EventRelay extends ObjectPoolEventAdapter
	{
		public void poolCheckOut(ObjectPoolEvent evt) { firePoolCheckOutEvent(); }
		public void poolCheckIn(ObjectPoolEvent evt) { firePoolCheckInEvent(); }
		public void maxPoolLimitReached(ObjectPoolEvent evt) { fireMaxPoolLimitReachedEvent(); }
		public void maxPoolLimitExceeded(ObjectPoolEvent evt) { fireMaxPoolLimitExceededEvent(); }
		public void maxSizeLimitReached(ObjectPoolEvent evt) { fireMaxSizeLimitReachedEvent(); }
		public void maxSizeLimitError(ObjectPoolEvent evt) { fireMaxSizeLimitErrorEvent(); }
		public void poolParametersChanged(ObjectPoolEvent evt) { fireParametersChangedEvent(); }
		public void poolReleased(ObjectPoolEvent evt) { firePoolReleasedEvent(); listeners.clear(); }
	}


	/**
	 * Default implementation of ConnectionValidator.
	 * This class simply checks a Connection with the <tt>isClosed()</tt> method.
	 */
	static class DefaultValidator implements ConnectionValidator
	{
		/**
		 * Validates a connection.
		 */
		public boolean isValid(Connection con)
		{
			try { return !con.isClosed(); }
			catch (SQLException e) { return false; }
		}
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -