日期:2014-05-16  浏览次数:20560 次

代理模式之静态代理---数据库连接池对象实现原理
   众所周知,数据库在建立链接的时候是很耗费时间的,如果每次操作数据库都要重新建立一下链接,这样对系统的性能就会造成影响。
  
    所谓数据库连接池就是在服务器启动时已经建立好一定数量的数据库链接对象,用的时候只需要在池里面拿就行了,而关闭的时候就是把拿出来的链接对象重新放入池中。
 
    其实说白了就是在服务器启动的时候就已经建立好一系列的数据库链接对象,并把这些对象放入一个容器里。

1.首先实现自己的数据源:
package com.zzg.jdbc.datasource;

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

public class MyDataSource {
	private String url;
	private String user;
	private String password;
	// 默认初始化链接数
        int initCount = 5;
	// 默认最大链接数
        int maxCount = 10;

	// 当前链接数
	private int currentCount = 0;

	/*
	 * 这里选择LinkedList而非ArrayList是因为获取链接对象 或释放链接对象是要反复的从容器中添加或删除节点,
	 * 而LinkedList是以链表的方式存储数据的, 所以在容器写操作上LinkedList在效率上要高于ArrayList
	 */
	LinkedList<Connection> connectionsPool = new LinkedList<Connection>();

	public MyDataSource(String url, String user, String password) {
		this.url = url;
		this.user = user;
		this.password = password;
		initPool();
	}

	public MyDataSource(String url, String user, String password,
			int initCount, int maxCount) {
		this.url = url;
		this.user = user;
		this.password = password;
		this.initCount = initCount;
		this.maxCount = maxCount;
		initPool();
	}

	/**
	 * 初始化的时候创建10个链接,并放入池中
	 */
	private void initPool() {
		System.out.println("initCount=" + this.initCount);
		try {
			for (int i = 0; i < this.initCount; i++) {
				this.connectionsPool.addLast(this.createConnection());
				this.currentCount++;
			}
		} catch (SQLException e) {
			throw new ExceptionInInitializerError(e);
		}
	}

	/**
	 * 从连接池中获取链接
	 * 
	 * @return
	 * @throws SQLException
	 */
	public Connection getConnection() throws SQLException {
		// 保证并发情况下拿到的不是同一个数据库链接对象
		synchronized (connectionsPool) {
			// 当数据库链接池中有链接时
			if (this.connectionsPool.size() > 0) {
				this.currentCount--;
				return this.connectionsPool.removeFirst();
			}
			// 当当前链接对象小于最大链接对象时创建链接对象
			if (this.currentCount < this.maxCount) {
				System.out.println("ddddddddddddddddd");
				this.currentCount++;
				return this.createConnection();
			}
			throw new SQLException("已没有链接可用");
		}

	}

	/**
	 * 释放链接,把链接重新放入池中
	 * 
	 * @param conn
	 * @throws SQLException
	 */
	public void free(Connection conn) throws SQLException {
	        this.currentCount++;
		this.connectionsPool.addLast(conn);
	}

	/**
	 * 创建链接
	 * 
	 * @return
	 * @throws SQLException
	 */
	private Connection createConnection() throws SQLException {
		return DriverManager.getConnection(url, user, password);
	}
}


2.建立获取数据库链接对象的帮助类
package com.zzg.jdbc.util;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import com.zzg.jdbc.datasource.MyDataSource;

public final class JdbcUtils {
	private static MyDataSource myDataSource = null;
	private static String url = "jdbc:mysql://localhost:3306/test";
	private static String user = "root";
	private static String password = "123456";

	private JdbcUtils() {
	}

	static {
		try {
			Class.forName("com.mysql.jdbc.Driver");
			myDataSource = new MyDataSource(url, user, password);
			//myDataSource = new MyDataSource(url, user, password,2,10);
		} catch (Exception e) {
			throw new ExceptionInInitializerError(e);
		}
	}

	/**
	 * 获取数据库链接对象(从连接池中获取)
	 * @return
	 * @throws SQLException
	 */
	public static Connection getConnection() throws SQLException {
		// return DriverManager.getConnection(url, user, password);
		return myDataSource.getConnection();
	}

	/**
	 * 释放链接对象(这里释放Connection是调用数据源的free方法)
	 * @param rs
	 * @param st
	 * @param conn
	 */
	public static void free(ResultSet rs, Statement st, Connection conn) {
		try {
			if (rs != null)
				rs.close();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			try {
				if (st != null)
					st.close();
			} catch (SQL