JDBC数据库连接池实现原理(手动实现)
一、普通的数据库连接
如下图所示,个用户获取数据库数据都要单独建立一个jdbc连接,当用户获取数据完成后再将连接释放,可见对cpu的资源消耗很大。

二、建立数据库连接池 数据库连接池创建后,每次获取数据库数据不需要另外建立连接,而是从连接池里拿出连接进行数据交互

三、手动实现连接池 核心:使用线程安全的Vector容器装连接Connection(C3P0使用的是LinkedList) PoolConfig.java数据库连接池属性配置 1
二、建立数据库连接池 数据库连接池创建后,每次获取数据库数据不需要另外建立连接,而是从连接池里拿出连接进行数据交互
三、手动实现连接池 核心:使用线程安全的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.Driver2
jdbc.url = jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncode=true&characterEncoding=utf-83
jdbc.userName=root4
jdbc.password=rootDBUtil.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
getResourceAsStream10
("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设置到本地变量ThreadLocal76
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
}
声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。
- 上一篇: 数据库连接池的工作原理
- 下一篇: 数据库阿里连接池 druid配置详解