数据库连接池:
>数据库的连接对象创建工作,比较消耗性能
>一开始先在内存中开辟一块空间(集合) , 先往池子里面放置 多个连接对象。 后面需要连接的话,直接从池子里面去。不要去自己创建连接了。 使用完毕, 要记得归还连接。确保连接对象能循环利用。即创建一个池子(容器) , 专门用来管理连接对象
连接池作用:
>更快响应速度
连接池里的连接在一开始就已经创建好了,后面如果需要直接拿就可以了,无需创建
>资源的重复利用、避免重复创建对象
连接对象使用完毕后,再归还到池子中进行统一管理即可
数据库连接池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);
}
}
}