一、普通的数据库连接
如下图所示,个用户获取数据库数据都要单独建立一个jdbc连接,当用户获取数据完成后再将连接释放,可见对cpu的资源消耗很大。
二、建立数据库连接池
数据库连接池创建后,每次获取数据库数据不需要另外建立连接,而是从连接池里拿出连接进行数据交互
三、手动实现连接池
核心:使用线程安全的Vector容器装连接Connection(C3P0使用的是LinkedList)
PoolConfig.java数据库连接池属性配置
1
/*
2
1.线程安全
3
2.有空闲连接的数量
4
3.有正在使用的连接数量
5
*/
6
public class PoolConfig{
7
/*
8
数据库jdbc属性
9
*/
10
private String driverName;//数据库的驱动类
11
private String url;//数据库的连接地址
12
private String userName;//数据库用户名
13
private String password;//数据库密码
14
15
/*
16
连接池配置
17
*/
18
private int minConn = 1;//空闲集合中最少连接数
19
private int maxConn = 5;//空闲集合最多的连接数
20
private int initConn = 5;//初始连接数
21
private int maxActiveConn = 10;//整个连接池(数据库)允许的最大连接数
22
private int waitTime = 1000;//单位毫秒,连接数不够时,线程等待的时间
23
private boolean isCheck = false;//数据库连接池是否启用自检机制(间隔一段时间检测连接池状态)
24
private long checkPeriod = 1000*30;//自检周期
25
26
//以下省略getter、setter方法...
27
}
db.properties配置文件
1
jdbc.driverName = com.mysql.jdbc.Driver
2
jdbc.url = jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncode=true&characterEncoding=utf-8
3
jdbc.userName=root
4
jdbc.password=root
DBUtil.java数据库工具包(数据库开发者调用)
1
public class DBUtil{
2
/* 静态数据库配置实体对象,程序运行时加载进内存 */
3
private static PoolConfig config = new PoolConfig();
4
5
static{//初始化加载配置文件
6
Properties prop = new Properties();
7
try{
8
prop.load(DBUtil.class.getClassLoader().
9
getResourceAsStream
10
("com/mypath/db/db.properties"));
11
//获取配置文件信息传入config连接池配置对象
12
config.setDriverName(prop.getProperty("jdbc.driverName"));
13
config.setUrl(prop.getProperty("jdbc.url"));
14
config.setUserName(prop.getProperty("jdbc.userName"));
15
config.setPassword(prop.getProperty("jdbc.password"));
16
//反射加载这个驱动(使用的是JDBC的驱动加载方式)
17
Class.forName(config.getDriverName());
18
}catch(IOException e){
19
e.printStackTrace();
20
}
21
}
22
23
private static ConnectionPool connPool = new ConnectionPool(config);
24
25
public static connection gerConnection(){
26
return connPool.getConnection();
27
}
28
29
public static connection gerCurrentConnection(){
30
return connPool.getCurrentConnection();
31
}
32
33
public static void closeConnection(Connection conn){
34
connPool.releaseConnection(conn);
35
}
36
}
ConnectionPool.java数据库连接池对象(根据配置创建对应连接池)
1
public class ConnectionPool{
2
private PoolConfig config;//连接池的配置对象
3
private int count;//记录连接池的连接数
4
private boolean isActive;//连接池是否被**
5
//空闲连接集合
6
private Vector<Connection> freeConn = new Vector<Connection>();
7
//正在使用的连接集合
8
private Vector<Connection> userConn = new Vector<Connection>();
9
//同一个线程无论请求多少次都使用同一个连接(使用ThreadLocal确保)
10
//每一个线程都私有一个连接
11
private static ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>();
12
/*
13
初始化连接池配置
14
*/
15
public ConnectionPool(PoolConfig config){
16
this.config = config;
17
}
18
19
/*
20
数据库连接池初始化
21
*/
22
public void init(){
23
for(int i=0;i<config.getInitConn();i++){//建立初始连接
24
//获取连接对象
25
Connection conn;
26
try{
27
conn = getNewConnection();
28
freeConn.add(conn);
29
count++;
30
}catche(SQLException e){
31
e.printStackTrace();
32
}
33
isActive = true;//连接池**
34
}
35
}
36
37
/*
38
获取新数据库连接
39
*/
40
private synchronized Connection getNewConnection() throws SQLException{
41
Connection conn = null;
42
conn = DriverManager.getConnection(config.getUrl(),
43
config.getUserName(),
44
config.getPassword());
45
return conn;
46
}
47
48
/*
49
从连接池获取连接
50
*/
51
public synchronized Conenction getConnection(){
52
Connection conn = null;
53
//当前连接总数小于配置的最大连接数才去获取
54
if(count<config.getMaxActiveConn()){
55
//空闲集合中有连接数
56
if(freeConn.size()>0){
57
conn = freeConn.get(0);//从空闲集合中取出
58
freeConn.remove(0);//移除该连接
59
}else{
60
conn = getNewConnection();//拿到新连接
61
count++;
62
}
63
if(isEnable(conn)){
64
useConn.add(conn);//添加到已经使用的连接
65
}else{
66
count--;
67
conn = getConnection();//递归调用到可用的连接
68
}
69
}else{//当达到最大连接数,只能阻塞等待
70
wait(config.getWaitTime());//线程睡眠了一段时间
71
conn = getConnection();//递归调用
72
}catch(Exception e){
73
e.printStackTrace();
74
}
75
//将获取的conn设置到本地变量ThreadLocal
76
threadLocal.set(conn);
77
return conn;
78
}
79
80
/*
81
把用完的连接放回连接池集合Vector中
82
*/
83
public synchronized void releaseConnection(Connection conn){
84
if(isEnable(conn)){
85
if(freeConn.size()<config.getMaxConn()){//空闲连接数没有达到最大
86
freeConn.add(conn);//放回集合
87
}else{
88
conn.close();
89
}
90
}
91
useConn.remove(conn);
92
count--;
93
threadLocal.remove();
94
notifyAll();//放回连接池后说明有连接可用,唤醒阻塞的线程获取连接
95
}
96
97
/*
98
获取当前线程的本地变量连接
99
*/
100
public Connection getCurrentConnection(){
101
return threadLocal.get();
102
}
103
104
/*
105
判断该连接是否可用
106
*/
107
private boolean isEnable(Connection conn){
108
if(conn == null){
109
return false;
110
}
111
if(conn.isClosed()){
112
return false;
113
}
114
return true;
115
}
116
}