一、数据库连接池概念
数据库连接池:负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏。这项技术能明显提高对数据库操作的性能。
二、背景
数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现得尤为突出。对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能指标。数据库连接池正是针对这个问题提出来的。
三、影响因素
数据库连接池在初始化时将创建一定数量的数据库连接放到连接池中,这些数据库连接的数量是由最小数据库连接数制约。无论这些数据库连接是否被使用,连接池都将一直保证至少拥有这么多的连接数量。连接池的最大数据库连接数量限定了这个连接池能占有的最大连接数,当应用程序向连接池请求的连接数超过最大连接数量时,这些请求将被加入到等待队列中。数据库连接池的最小连接数和最大连接数的设置要考虑到下列几个因素:
1. 最小连接数
是连接池一直保持的数据库连接,所以如果应用程序对数据库连接的使用量不大,将会有大量的数据库连接资源被浪费。
2. 最大连接数
是连接池能申请的最大连接数,如果数据库连接请求超过此数,后面的数据库连接请求将被加入到等待队列中,这会影响之后的数据库操作。
3. 最小连接数与最大连接数差距
最小连接数与最大连接数相差太大,那么最先的连接请求将会获利,之后超过最小连接数量的连接请求等价于建立一个新的数据库连接。不过,这些大于最小连接数的数据库连接在使用完不会马上被释放,它将被放到连接池中等待重复使用或是空闲超时后被释放。
四、原理
连接池基本的思想是在系统初始化的时候,将数据库连接作为对象存储在内存中,当用户需要访问数据库时,并非建立一个新的连接,而是从连接池中取出一个已建立的空闲连接对象。使用完毕后,用户也并非将连接关闭,而是将连接放回连接池中,以供下一个请求访问使用。而连接的建立、断开都由连接池自身来管理。同时,还可以通过设置连接池的参数来控制连接池中的初始连接数、连接的上下限数以及每个连接的最大使用次数、最大空闲时间等等。也可以通过其自身的管理机制来监视数据库连接的数量、使用情况等。
五、实现
一般来说,Java应用程序访问数据库的过程:
1、装载数据库驱动程序;
2、通过jdbc创建数据库连接;
3、访问数据库,执行sql语句;
4、关闭数据库连接。
编写连接池需实现java.sql.DataSource接口。DataSource接口中定义了两个重载的getConnection方法:
· Connection getConnection()
· Connection getConnection(String username, String password)
实现DataSource接口,并实现连接池功能的步骤:
1. 在DataSource构造函数中批量创建与数据库的连接,并把创建的连接加入LinkedList对象中。
2. 实现getConnection方法,让getConnection方法每次调用时,从LinkedList中取一个Connection返回给用户。
3. 当用户使用完Connection,调用Connection.close()方法时,Collection对象应保证将自己返回到LinkedList中,而不要把conn还给数据库。Collection保证将自己返回到LinkedList中是此处编程的难点。
6、代码实现
package com.example.jdbcConnection;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Liuxd on 2018/8/19.
*/
public class TestC3p0 {
private static Connection conn;
private static ComboPooledDataSource dataSource;
static {
try {
//获得c3p0连接池对象
dataSource = new ComboPooledDataSource();
dataSource.setUser("root");
dataSource.setPassword("root");
dataSource.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/foo?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2b8&useSSL=false");
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setInitialPoolSize(2);//初始化池大小
dataSource.setMaxIdleTime(30);//最大空闲时间
dataSource.setMaxPoolSize(20);//最多连接数
dataSource.setMinPoolSize(2);//最少连接数
dataSource.setMaxStatements(50);//每次最多可以执行多少个批处理语句
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 查询
*/
private static List<Object[]> query() {
List<Object[]> list = new ArrayList<Object[]>();
try {
// 获取数据库连接
conn = dataSource.getConnection();
// 查询sql
String sql = "select * from user";
// 读取数据
PreparedStatement preparedStatement = conn.prepareStatement(sql);
//结果集
ResultSet resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
int uid = resultSet.getInt("uid");
String name = resultSet.getString("name");
Integer age = resultSet.getInt("age");
String phone = resultSet.getString("phone");
String passwd = resultSet.getString("passwd");
Object[] objects = new Object[]{uid, name, age, phone, passwd};
list.add(objects);
}
resultSet.close();
preparedStatement.close();
//Connection连接对象归还数据库连接池
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
return list;
}
/**
* 新增
*/
private static void add(String name, int age, String phone, String passwd) {
try {
// 获取数据库连接
conn = dataSource.getConnection();
String insertSql = "insert into `user` (`name`, `age`, `phone`, `passwd`) values(?,?,?,?)";
PreparedStatement ps = conn.prepareStatement(insertSql);
ps.setString(1, name);
ps.setInt(2, age);
ps.setString(3, phone);
ps.setString(4, passwd);
int row = ps.executeUpdate();
System.out.println("新增结果: " + row);
ps.close();
//Connection连接对象归还数据库连接池
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 修改
*/
private static void update(int uid, String name, int age, String phone, String passwd) {
try {
// 获取数据库连接
conn = dataSource.getConnection();
String updateSql = "UPDATE USER t SET t.name=? ,t.age=?,t.phone=?,t.passwd=? WHERE t.uid=?";
PreparedStatement preparedStatement = conn.prepareStatement(updateSql);
preparedStatement.setString(1, name);
preparedStatement.setInt(2, age);
preparedStatement.setString(3, phone);
preparedStatement.setString(4, passwd);
preparedStatement.setLong(5, uid);
// 执行sql
preparedStatement.executeUpdate();
int row = preparedStatement.executeUpdate();
System.out.println("修改结果: " + row);
//Connection连接对象归还数据库连接池
conn.close();
preparedStatement.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 删除
*/
private static void deleteById(int uid) {
try {
// 获取数据库连接
conn = dataSource.getConnection();
String sql = "delete from USER where uid=?";
PreparedStatement preparedStatement = conn.prepareStatement(sql);
preparedStatement.setInt(1, uid);
int row = preparedStatement.executeUpdate();
System.out.println("删除结果: " + row);
preparedStatement.close();
//Connection连接对象归还数据库连接池
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
/**
* 1、验证连接数
*/
for (int i = 0; i < 10; i++) {
Connection connection = null;
try {
connection = dataSource.getConnection();
System.out.println(connection.toString());
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (null != connection) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
/**
* 2、查询
*/
List<Object[]> list = query();
if (null != list && list.size() > 0) {
for (int i = 0; i < list.size(); i++) {
Object[] objects = list.get(i);
for (int j = 0; j < objects.length; j++) {
System.out.print(objects[j] + " ");
}
System.out.println();
}
}
/**
* 3、新增
*/
String name = "乐乐";
int age = 17;
String phone = "13800138001";
String passwd = "admin123";
add(name, age, phone, passwd);
/**
* 4、修改
*/
update(12, name, age, phone, passwd);
/**
* 5、删除
*/
deleteById(3);
}
}
7、数据库脚本
create table `user` (
`uid` bigint (20),
`name` varchar (75),
`age` int (3),
`phone` varchar (360),
`passwd` varchar (36)
);
insert into `user` (`uid`, `name`, `age`, `phone`, `passwd`) values('1','张伦','12','13800138001','admin');
insert into `user` (`uid`, `name`, `age`, `phone`, `passwd`) values('4','李威','12','23','admin');
insert into `user` (`uid`, `name`, `age`, `phone`, `passwd`) values('5','莉莉','18','13800138000','abc123');
insert into `user` (`uid`, `name`, `age`, `phone`, `passwd`) values('6','小宝','18','13800138000','abc123');
insert into `user` (`uid`, `name`, `age`, `phone`, `passwd`) values('7','李金刚','18','13800138000','abc123');
insert into `user` (`uid`, `name`, `age`, `phone`, `passwd`) values('8','李金刚','18','13800138000','abc123');
insert into `user` (`uid`, `name`, `age`, `phone`, `passwd`) values('9','菲菲','6','13800138000','abc123');
insert into `user` (`uid`, `name`, `age`, `phone`, `passwd`) values('10','李赛','12','18890999090','123123');
insert into `user` (`uid`, `name`, `age`, `phone`, `passwd`) values('11','李赛','12','18890999090','123123');
insert into `user` (`uid`, `name`, `age`, `phone`, `passwd`) values('12','乐乐','17','13800138001','admin123');
insert into `user` (`uid`, `name`, `age`, `phone`, `passwd`) values('13','李赛','12','18890999090','123123');
insert into `user` (`uid`, `name`, `age`, `phone`, `passwd`) values('14','李赛','12','18890999090','123123');
insert into `user` (`uid`, `name`, `age`, `phone`, `passwd`) values('15','李赛','12','18890999090','123123');
insert into `user` (`uid`, `name`, `age`, `phone`, `passwd`) values('16','李赛','12','18890999090','123123');
insert into `user` (`uid`, `name`, `age`, `phone`, `passwd`) values('17','李赛','12','18890999090','123123');
insert into `user` (`uid`, `name`, `age`, `phone`, `passwd`) values('18','乐乐','17','13800138001','admin123');
参考: