一、为什么要使用数据库连接池
我们都知道数据库的连接一般都按照:加载数据库驱动,建立数据库连接,执行sql语句,断开数据库连接的步骤来进行。
然而,在实际的开发应用中,建立连接是一个费时的活动,每一次请求都要建立一次数据库连接,每次向数据库建立连接的时候都要将Connection对象加载到内存中,若遇到访问量剧增的情况,势必会造成系统资源和时间的大量消耗,严重的甚至会造成服务器的崩溃。而且,对于每一次的数据库连接,使用完后都得断开,数据库的连接资源不能得到很好的重复利用。如果程序出现异常而未能关闭连接,将会导致数据库系统中的内存泄露,最终导致重启数据库。
因此,为了能够解决上述问题,在实际开发中通常使用数据库连接池技术。
二、数据库连接池是什么
数据库连接池,就是:为数据库连接建立一个“缓冲池”。预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,我们只需要从缓冲池中取出一个连接拿来用,使用完我们再放回去。
数据库连接池负责分配,管理和释放数据库的连接,它允许应用程序重复使用一个现有的数据库连接而不是重新建立一个。数据库连接池对现有连接资源进行管理和调配。
三、数据库连接池的优势
- 资源重用:避免了频繁创建、释放连接引起的大量性能开销
- 更快的响应速度:对于业务的请求处理,直接利用现有的连接,避免数据库连接初始化和释放过程的时间开销
- 新的资源分配手段:对于多程序共享同一数据库,可在应用层通过数据库连接池配置某一程序能够使用的最大数据库连接数
- 统一的连接管理,避免数据库泄露:可根据预先的连接占用超时设定,强制收回被占用的连接,从而避免了资源泄露
四、数据库连接池的工作原理
1、连接池的建立:
在系统初始化时,连接池会根据系统的配置来建立,并在池中建立若干个连接对象,以便使用时能从连接池中获取。为了避免连接随意建立和关闭造成的系统开销,连接池中的连接不能随意创建和关闭。Java中提供了很多的容器类,可以方便的构建连接池。
2、连接池的管理:
连接池的管理策略时连接池机制的核心,会对系统性能 造成很大的影响。当线程请求数据库连接时,首先查看连接池中是否有空闲的连接,如果有,则将连接分配给线程使用,如果没有,则查看当前所开的连接数是否达到上限,如果没有则重新创建一个连接。如果达到上限,则按设定的最大等待时间等待连接释放,然后再进行分配,如果超过设定的最大等待时间,还是没有空闲连接,则抛出异常。
注意:当线程释放数据库连接时,先判断该连接的引用次数是否超过了规定值,如果超过了就从连接池中删除该连接,否则保留。 该策略是为了保证数据库连接的有效服用,避免了频繁建立所带来的资源开销。
3、连接池的关闭
当应用程序退出时,关闭连接池中的所有连接,释放连接池中的相关资源。
4、连接池的配置
采用minConn和maxConn来限制连接的数量。minConn是应用启动时连接池所创建的连接数,如果该值过大,启动将变慢,但是启动后响应更快;如果该值过小,启动时很快,但是最初使用会因为连接不足而延缓执行速度,因此minConn的值需要反复实验来找到饱和点。maxConn时连接池中的最大连接数,设定连接池的最大连接数来防止系统无尽的与数据库创建连接。
五、自定义数据库连接池
下面我们通过自定义的一个简单的连接池来了解一下连接池大致的工作原理
package com.connection;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.LinkedList;
public class ConnectionPool {
private static LinkedList<Connection> poolConnections=new LinkedList<Connection>();
//模拟初始化连接池,在连接池中建立三个连接
static{
try {
for(int i=0;i<3;i++){
Class.forName("com.mysql.jdbc.Driver");
Connection connection=DriverManager.getConnection("jdbc:mysql://localhost:3306/MF","root","root");
poolConnections.add(connection);//将连接加入到连接池
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
//获取连接
public static Connection getConnection () {
return poolConnections.removeFirst();//将连接池中的第一个连接取出并返回
}
//将连接放回连接池
public static void returnConnection (Connection conn) {
if(conn!=null){
poolConnections.add(conn);
}
}
}
package com.connection;
import java.sql.Connection;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
for(int i=0;i<5;i++){
//从连接池获得连接
try{
Connection connection=ConnectionPool.getConnection();
System.out.println(connection);
//将连接放回连接池
ConnectionPool.returnConnection(connection);
}catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
}
执行测试类结果:
控制台显示的是连接池中的Connection对象 。
上述实例模拟了连接池的实现过程,在实际开发中已有很多性能优良的数据库连接池可以使用,开发者只需理解原理,无需自己定义连接池。
为了方便地利用数据库连接池进行开发,java语言 为数据库连接池提供了公共的接口DataSource,第三方数据库连接池一般都要实现该接口,从而使得java程序能够在不同的数据库连接池之间进行切换。
目前常用的数据库连接池C3P0和DBCP,它们都是实现DataSource接口的,详情请看下一节: