为什么要用数据库连接池?
对于一个简单的数据库应用,由于对于数据库的访问不是很频繁。这时可以简单地在需要访问数据库时,就新创建一个连接,用完后就关闭它,这样做也不会带来什么明显的性能上的开销。
但是对于一个复杂的数据库应用,情况就完全不同了。频繁的建立、关闭连接,会极大的减低系统的性能,因为对于连接的使用成了系统性能的瓶颈。
此时便有了数据库连接池的用武之地、
什么是数据库连接池?
官方:数据库连接池(Connection pooling)是程序启动时建立足够的数据库连接,并将这些连接组成一个连接池,由程序动态地对池中的连接进行申请,使用,释放。
个人理解:创建数据库连接是一个很耗时的操作,也容易对数据库造成安全隐患。所以,在程序初始化的时候,集中创建多个数据库连接,并把他们集中管理,供程序使用,可以保证较快的数据库读写速度,还更加安全可靠。
外部使用者可通过getConnection 方法获取连接,使用完毕后再通过releaseConnection 方法将连接返回,注意此时连接并没有关闭,而是由连接池管理器回收,并为下一次使用做好准备。
数据库连接池技术带来的优势:
1. 资源重用
由于数据库连接得到重用,避免了频繁创建、释放连接引起的大量性能开销。在减少系统消耗的基础上,另一方面也增进了系统运行环境的平稳性(减少内存碎片以及数据库临时进程/线程的数量)。
2. 更快的系统响应速度
数据库连接池在初始化过程中,往往已经创建了若干数据库连接置于池中备用。此时连接的初始化工作均已完成。对于业务请求处理而言,直接利用现有可用连接,避免了数据库连接初始化和释放过程的时间开销,从而缩减了系统整体响应时间。
3. 新的资源分配手段
对于多应用共享同一数据库的系统而言,可在应用层通过数据库连接的配置,实现数据库连接池技术,几年钱也许还是个新鲜话题,对于目前的业务系统而言,如果设计中还没有考虑到连接池的应用,那么…….快在设计文档中加上这部分的内容吧。某一应用最大可用数据库连接数的限制,避免某一应用独占所有数据库资源。
4. 统一的连接管理,避免数据库连接泄漏
在较为完备的数据库连接池实现中,可根据预先的连接占用超时设定,强制收回被占用连接。从而避免了常规数据库连接操作中可能出现的资源泄漏。一个最小化的数据库连接池实现.
连接池类是对某一数据库所有连接的“缓冲池”,主要实现以下功能:①从连接池获取或创建可用连接;②使用完毕之后,把连接返还给连接池;③在系统关闭前,断开所有连接并释放连接占用的系统资源;④还能够处理无效连接(原来登记为可用的连接,由于某种原因不再可用,如超时,通讯问题),并能够限制连接池中的连接总数不低于某个预定值和不超过某个预定值。
数据库连接池实现
c3p0是一个优秀的连接池,性能也十分可靠。本文就以c3p0连接池为例、
首先到http://sourceforge.net/projects/c3p0/下载相应的jar包,总共三个,如下图所示。
本例子连接mysql数据库,所以还有连接mysql要用的jar包,相信大家都不陌生、
为了更直观的理解使用连接池和不使用的区别:以下例子大家可以参考、
别忘了引入jar包哦、、、(共四个jar包,三个类)
1.测试类:
package c3p0;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class ConnectionDemo {
public static void main(String[] args) throws SQLException {
long totleTime1 = 0;
long totleTime2 = 0;
System.out.println("使用连接池................................");
for (int i = 0; i < 20; i++) {
long beginTime = System.currentTimeMillis();
Connection conn = ConnectionManager.getInstance().getConnection();
try {
PreparedStatement pstmt = conn.prepareStatement("select * from customer");
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
// do nothing...
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
long endTime = System.currentTimeMillis();
long countTime = endTime - beginTime ;
totleTime1 += countTime;
System.out.println("第" + (i + 1) + "次执行花费时间为:" + (countTime)+" 总时间:"+totleTime1);
}
System.out.println("不使用连接池................................");
for (int i = 0; i < 20; i++) {
long beginTime = System.currentTimeMillis();
MysqlDataSource mds = new MysqlDataSource();
mds.setURL("jdbc:mysql://localhost:3306/crm?useSSL=false");
mds.setUser("root");
mds.setPassword("123456");
Connection conn = mds.getConnection();
try {
PreparedStatement pstmt = conn.prepareStatement("select * from customer");
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
// do nothing...
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
long endTime = System.currentTimeMillis();
long countTime = endTime - beginTime ;
totleTime2 += countTime;
System.out.println("第" + (i + 1) + "次执行花费时间为:"
+ (countTime)+" 总时间:"+totleTime2);
}
}
}
2.使用数据库连接池的类:
package c3p0;
import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.SQLException;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public final class ConnectionManager {
//使用单例模式创建数据库连接池
private static ConnectionManager instance;
private static ComboPooledDataSource dataSource;
private ConnectionManager() throws SQLException, PropertyVetoException {
dataSource = new ComboPooledDataSource();
dataSource.setUser("root"); //用户名
dataSource.setPassword("123456"); //密码
dataSource.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/crm?useSSL=false");//数据库地址
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setInitialPoolSize(5); //初始化连接数
dataSource.setMinPoolSize(1);//最小连接数
dataSource.setMaxPoolSize(10);//最大连接数
dataSource.setMaxStatements(50);//最长等待时间
dataSource.setMaxIdleTime(60);//最大空闲时间,单位毫秒
}
public static final ConnectionManager getInstance() {
if (instance == null) {
try {
instance = new ConnectionManager();
} catch (Exception e) {
e.printStackTrace();
}
}
return instance;
}
public synchronized final Connection getConnection() {
Connection conn = null;
try {
conn = dataSource.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
}
3.不使用数据库连接池的类:
package c3p0;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class MysqlDataSource
{
String url = "";
String user = "";
String password = "";
//连接
private Connection conn = null;
//静态块
static
{
//实例化驱动类
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
System.out.println("mysql驱动装载失败");
e.printStackTrace();
}
}
//取得数据库连接
public Connection getConnection()
{
try {
conn = DriverManager.getConnection(url, user, password);
} catch (SQLException e) {
// TODO Auto-generated catch block
System.out.println("无法取得数据库连接");
e.printStackTrace();
}
return conn;
}
//关闭连接
public void closeConnection()
{
try
{
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
System.out.println("无法关闭数据库联接");
e.printStackTrace();
}
}
public void setURL(String url) {
this.url = url;
}
public void setUser(String user) {
this.user = user;
}
public void setPassword(String password) {
this.password = password;
}
}
控制台结果:
使用连接池首次创建连接加载时间较长,但之后响应速度明显较快;
与不使用连接池有明显不同、
如果对您有所帮助,请点赞,谢谢、、、