数据库连接池

>数据库的连接对象创建工作,比较消耗性能

>一开始先在内存中开辟一块空间(集合) , 先往池子里面放置 多个连接对象。  后面需要连接的话,直接从池子里面去。不要去自己创建连接了。  使用完毕, 要记得归还连接。确保连接对象能循环利用。即创建一个池子(容器) , 专门用来管理连接对象

连接池作用

>更快响应速度

连接池里的连接在一开始就已经创建好了,后面如果需要直接拿就可以了,无需创建

>资源的重复利用、避免重复创建对象

连接对象使用完毕后,再归还到池子中进行统一管理即可

数据库连接池MyDataSource代码

/*
 * 这是一个数据库连接池
 * 一开始先往池子里面放10个连接
 * 
 * 1、开始创建10个连接
 * 2、来的程序通过getConnection获取连接
 * 3、用完之后,使用addBack归还连接
 * 4、扩容
 */

public class MyDataSource implements DataSource {

	List<Connection> list = new ArrayList<Connection>();

	public MyDataSource() {
		for (int i = 0; i < 10; i++) {
			Connection conn = JDBCUtil.getCoon();
			list.add(conn);
		}
	}

	//该连接池对外公布的获取连接的方法
	@Override
	public Connection getConnection() throws SQLException {
		System.out.println(list.size());
		//来拿连接的时候,先看看池子里还有没有
		if(list.size() == 0) {
			for(int i = 0;i<3;i++) {
				Connection conn = JDBCUtil.getCoon();
				list.add(conn);
			}
		}
	//remove(0)----->移除第一个。移除的是集合里的第一个。
		Connection conn = list.remove(0);
		return conn;
	}
	
	/*
	 * 用完之后,记得归还
	 */
	public void addBack(Connection conn) {
		list.add(conn);
	}
...........
}

测试代码为:

public class TestPool {

	@Test
	public void testPool() {
		Connection conn = null;
		PreparedStatement ps = null;
		MyDataSource dataSource = new MyDataSource();
		try {
			conn = dataSource.getConnection();

			String sql = "insert into account values (null,'夏虹',1000)";
			ps = conn.prepareStatement(sql);
			ps.executeUpdate();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			try {
				ps.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			dataSource.addBack(conn);
		}
	}
}

以上代码的问题是:

1、对象没有做成单例

在哪里使用,都需要new MyDataSource(). 这就会造成有多个对象的情况出现,那就不只是一个池子了

2、需要额外记住addBack方法

sun公司定义的数据库连接池里面并没有这个addBack方法,所以谁需要用我们这个连接池,需要记住这个方法是用来回收连接对象的。

3、无法面向接口编程。 

由于我们的连接池直接定义成了一个类,并且里面还额外添加了一个addBack方法,这就造成了我们无法面向接口编程。

为了解决上面出现的问题:

不打算添加 addBack 方法, 而是扩展原来的 close 方法。 让 close 方法,不关闭连接,而是把连接对象归还给池子。要想实现这个需求,有以下几种方式:

1. 直接修改JDBC 里面的那个 Connection 接口的具体实现。让它的 close 方法别关闭连接,而是变成回收连接对象。

答案: 无法办到。 咱们没把发修改人家的源代码

2. 既然不能直接修改,那么我们改成自己定义一个类,然后继承那个 Connection 接口的实现类, 然后在它的 close 方法基础上,加入我们的回收逻辑。

答案: 无法办到, 因为我们根本不知道 Connection 接口的实现类是哪一个. 

3. 使用装饰者模式来实现。

答案: 可以办到。 

使用装饰者模式后的代码是:

定义一个类实现Connection 接口:

注意,使用了Connection接口的哪个方法

public class ConnectionWrap implements Connection{
	
	Connection conn = null;
	List<Connection> list = null;
	
	public ConnectionWrap(Connection conn,List<Connection> list) {
		super();
		this.conn = conn;
		this.list = list;
	}

	@Override
	public void close() throws SQLException {
		System.out.println("有人来归还连接对象了。归还之前,池子里面是:" + list.size());
//		conn.close();
		list.add(conn);
		System.out.println("有人来归还连接对象了。归还之后,池子里面是:" + list.size());
	}
	
	@Override
	public PreparedStatement prepareStatement(String sql) throws SQLException {
		return conn.prepareStatement(sql);
	}
........
}

数据库连接池 MyDataSource代码为:

/*
 * 这是一个数据库连接池
 * 一开始先往池子里面放10个连接
 * 
 * 1、开始创建10个连接
 * 2、来的程序通过getConnection获取连接
 * 3、用完之后,使用addBack归还连接
 * 4、扩容
 */

public class MyDataSource implements DataSource {

	List<Connection> list = new ArrayList<Connection>();

	public MyDataSource() {
		for (int i = 0; i < 10; i++) {
			Connection conn = JDBCUtil.getCoon();
			list.add(conn);
		}
	}

	//该连接池对外公布的获取连接的方法
	@Override
	public Connection getConnection() throws SQLException {
		System.out.println(list.size());
		//来拿连接的时候,先看看池子里还有没有
		if(list.size() == 0) {
			for(int i = 0;i<3;i++) {
				Connection conn = JDBCUtil.getCoon();
				list.add(conn);
			}
		}
	//remove(0)----->移除第一个。移除的是集合里的第一个。
		Connection conn = list.remove(0);
		
		Connection connection = new ConnectionWrap(conn,list);
		return connection;
	}
	
..........
}

test代码为:

public class TestPool {

	@Test
	public void testPool() {
		Connection conn = null;
		PreparedStatement ps = null;
		MyDataSource dataSource = new MyDataSource();
		try {
			conn = dataSource.getConnection();

			String sql = "insert into account values (null,'夏虹',1000)";
			ps = conn.prepareStatement(sql);
			ps.executeUpdate();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			try {
				ps.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
//			dataSource.addBack(conn);
			JDBCUtil.release(conn, ps);
		}
	}

}