9、数据库连接池的实现

        编写数据库连接池的步骤:

1、要实现java.sql.DataSource接口,

2、在DataSource的构造函数里面,批量创建与数据库的连接.并把创建的数据库连接加入LinkedList. (因为用LinkedList便于增加和删除)

3、实现getConnection()方法,每次调用getConnection()方法时,在LinkedList中,去获取一个连接,并返回给用户

4、当用户用完连接Connection时,调用conn.close()方法时,应该将连接Connection返回给LinkedList,而不是返回给数据库.

5、编程的难点在于,当用户用完连接Connection时,调用conn.close()方法时,应该将连接Connection返回给LinkedList,而不是返回给数据库.利用动态代理来实现

6、自己手动实现的数据库连接池JDBCPool代码,如下

      

package com.jdbc.enhancegenericitypool.utils;

import java.io.PrintWriter;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.LinkedList;
import java.util.Properties;
import java.util.logging.Logger;

import javax.sql.DataSource;

import com.jdbc.utils.MyJDBCUtils;

/**
 * 只需要重写getConnection()方法即可
 *
 */
public class JDBCPool implements DataSource {
	/**
	 * 为了程序的更好的解耦合,利用Properties文件保存连接Mysql的配置文件
	 */
	private static Properties config = new Properties();
	/**
	 * 用于保存连接池中的Connection
	 */
	private LinkedList<Connection> connPool = new LinkedList<Connection>();
	/**
	 * 默认Connection初始化的数量为3个
	 */
	private int connCount = 3;
	// 在静态代码块里面,加载并且初始化Mysql的配置
	static {
		try {
			config.load(MyJDBCUtils.class.getClassLoader().getResourceAsStream(
					"db.properties"));
			Class.forName(config.getProperty("driver"));
		} catch (Exception e) {
			throw new ExceptionInInitializerError(e);
		}
	}

	/**
	 * 1、在JDBCPool的构造方法中,初始化连接池的数量
	 */
	public JDBCPool() {
		for (int i = 0; i < connCount; i++) {
			connPool.add(getConnectionToConnPool());
		}
	}

	/**
	 * 获取一个数据库的连接,并加入到数据库连接池connPool中
	 * 
	 * @return
	 */
	private Connection getConnectionToConnPool() {
		Connection conn = null;
		try {
			conn = DriverManager.getConnection(config.getProperty("url"),
					config.getProperty("username"),
					config.getProperty("password"));
		} catch (SQLException e) {
			throw new RuntimeException("获取连接Mysql数据库连接失败");
		}
		return conn;
	}

	@Override
	public PrintWriter getLogWriter() throws SQLException {
		return null;
	}

	@Override
	public void setLogWriter(PrintWriter out) throws SQLException {

	}

	@Override
	public void setLoginTimeout(int seconds) throws SQLException {

	}

	@Override
	public int getLoginTimeout() throws SQLException {
		return 0;
	}

	@Override
	public Logger getParentLogger() throws SQLFeatureNotSupportedException {
		return null;
	}

	@Override
	public <T> T unwrap(Class<T> iface) throws SQLException {
		return null;
	}

	@Override
	public boolean isWrapperFor(Class<?> iface) throws SQLException {
		return false;
	}

	@Override
	public Connection getConnection() throws SQLException {

		if (connPool.size() <= 0) {
			throw new RuntimeException("服务器繁忙");
		}
		// 获取数据库的连接池里面的Connection
		Connection conn = connPool.removeFirst();
		// 使用动态代理的方式,来加强Connection的close()方法,
		// 是的连接的释放,会回到conns中,而不是数据库连接池中
		Connection proxyConn = (Connection) Proxy.newProxyInstance(this
				.getClass().getClassLoader(), conn.getClass().getInterfaces(),
				new MyInvocationHabdle(conn) {
				});
		return proxyConn;
	}

	@Override
	public Connection getConnection(String username, String password)
			throws SQLException {
		return null;
	}

	// 创建内部类MyInvocationHabdle,用于动态代理
	public class MyInvocationHabdle implements InvocationHandler {
		/**
		 * 保存被代理的对象
		 */
		private Connection conn;

		public MyInvocationHabdle(Connection conn) {
			this.conn = conn;
		}

		@Override
		public Object invoke(Object proxy, Method method, Object[] args)
				throws Throwable {
			// 当调用close方法时,把数据库的连接返回给conns,

			if ("close".equals(method.getName())) {
				connPool.add(conn);
				return null;
			}
			// 调用其他方法时,直接返回
			return method.invoke(conn, args);
		}
	}

}

7、对于连接池的测试代码,证明获取的数据库的连接就是连接池里面的

package com.jdbc.enhancegenericitypool.utils;

import java.sql.Connection;
import java.sql.SQLException;

public class PoolTest {

	public static void main(String[] args) throws SQLException {
		JDBCPool jdbcPool = new JDBCPool();
		for (int i = 0; i < 9; i++) {
			Connection connection = jdbcPool.getConnection();
			System.out.println(connection);
			connection.close();
		}
	}
}

8、程序的运行代码如下

9、数据库连接池的实现_第1张图片

       

你可能感兴趣的:(动态代理,mysql,数据库连接池,jdbc连接mysql数据库)