coreconnectionpool.java

来自「Jodd是一个开源的公用Java基础类库」· Java 代码 · 共 192 行

JAVA
192
字号
package jodd.db.pool;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;

/**
 * A class for preallocating, recycling, and managing JDBC connections.
 *
 * It uses threads for opening a new connection. When no connection
 * availiable it will wait until a connection is released.
 *
 * @2do add thread for cleaning non-necessary connections, from time to time.
 */
public class CoreConnectionPool implements Runnable, ConnectionPool {

	// ---------------------------------------------------------------- properties

	private String driver;
	public void setDriver(String s) {
		driver = s;
	}
	
	private String url;
    public void setUrl(String s) {
		url = s;
	}

	private String user;
    public void setUser(String s) {
		user = s;
	}

	private String password;
    public void setPassword(String s) {
		password = s;
	}

	private int maxConnections = 10;
    public void setMaxConnections(int i) {
		maxConnections = i;
	}

	private int minConnections = 5;
    public void setMinConnections(int i) {
		minConnections = i;
	}

	private boolean waitIfBusy = false;
	public void setWaitIfBusy(boolean b) {
		waitIfBusy = b;
	}

	// ---------------------------------------------------------------- init

	private ArrayList availableConnections, busyConnections;
	private boolean connectionPending = false;

	public CoreConnectionPool() {
	}

	public void init() throws SQLException {
		try {
			Class.forName(driver);
		} catch (ClassNotFoundException cnfe) {
			throw new SQLException("Database driver not found: " + driver);
		}
		if (minConnections > maxConnections) {
			minConnections = maxConnections;
		}
		availableConnections = new ArrayList(minConnections);
		busyConnections = new ArrayList();
		for (int i = 0; i < minConnections; i++) {
			availableConnections.add(DriverManager.getConnection(url, user, password));
		}
	}

	// ---------------------------------------------------------------- get/free

	public synchronized Connection getConnection() throws SQLException {
		if (!availableConnections.isEmpty()) {
			int lastIndex = availableConnections.size() - 1;
			Connection existingConnection = (Connection) availableConnections.get(lastIndex);
			availableConnections.remove(lastIndex);
			
			// If connection on available list is closed (e.g., it timed out), then remove it from available list
			// and repeat the process of obtaining a connection. Also wake up threads that were waiting for a
			// connection because maxConnection limit was reached.
			if (existingConnection.isClosed()) {
				notifyAll();				 // freed up a spot for anybody waiting
				return getConnection();
			} else {
				busyConnections.add(existingConnection);
				return existingConnection;
			}
		} else {
			// Three possible cases:
			// 1) You haven't reached maxConnections limit. So establish one in the background if there isn't
			//    already one pending, then wait for the next available connection (whether or not
			//    it was the newly established one).
			// 2) You reached maxConnections limit and waitIfBusy flag is false. Throw SQLException in such a case.
			// 3) You reached maxConnections limit and waitIfBusy flag is true. Then do the same thing as in second
			//    part of step 1: wait for next available connection.

			if ((totalConnections() < maxConnections) && !connectionPending) {
				makeBackgroundConnection();
			} else if (!waitIfBusy) {
				throw new SQLException("Connection limit reached");
			}
			// wait for either a new connection to be established (if you called makeBackgroundConnection) or for
			// an existing connection to be freed up.
			try {
				wait();
			} catch (InterruptedException ie) {
			}
			// someone freed up a connection, so try again.
			return getConnection();
		}
	}

	/**
	 * You can't just make a new connection in the foreground when none are
	 * available, since this can take several seconds with a slow network
	 * connection. Instead, start a thread that establishes a new connection,
	 * then wait. You get woken up either when the new connection is established
	 * or if someone finishes with an existing connection.
	 */
	private void makeBackgroundConnection() {
		connectionPending = true;
		try {
			Thread connectThread = new Thread(this);
			connectThread.start();
		} catch (OutOfMemoryError oome) {
			// give up on new connection
		}
	}

	public void run() {
		try {
			Connection connection = DriverManager.getConnection(url, user, password);
			synchronized(this) {
				availableConnections.add(connection);
				connectionPending = false;
				notifyAll();
			}
		} catch (Exception e) {	// SQLException or OutOfMemory
			// give up on new connection and wait for existing one to free up.
		}
	}

	public synchronized void freeConnection(Connection connection) {
		busyConnections.remove(connection);
		availableConnections.add(connection);
		// wake up threads that are waiting for a connection
		notifyAll();
	}

	public synchronized int totalConnections() {
		return (availableConnections.size() + busyConnections.size());
	}

	// ---------------------------------------------------------------- close

	/**
	 * Close all the connections. Use with caution: be sure no connections are in
	 * use before calling. Note that you are not <I>required</I> to call this
	 * when done with a ConnectionPool, since connections are guaranteed to be
	 * closed when garbage collected. But this method gives more control
	 * regarding when the connections are closed.
	 */
	public synchronized void close() {
		closeConnections(availableConnections);
		availableConnections = new ArrayList();
		closeConnections(busyConnections);
		busyConnections = new ArrayList();
	}

	private void closeConnections(ArrayList connections) {
		try {
			for (int i=0; i<connections.size(); i++) {
				Connection connection = (Connection)connections.get(i);
				if (!connection.isClosed()) {
					connection.close();
				}
			}
		} catch (SQLException sqle) {
			// Ignore errors; garbage collect anyhow
		}
	}
}

⌨️ 快捷键说明

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