数据库链接池原生java-api实现

通常在做java-web开发时,最需要做的就是配置数据库连接;从简单的jdbc直接使用到使用第三方分装的orm。在使用传统的jdbc进行数据库操作时,经常是当要进行一个数据库操作时,就开启一个数据库连接,操作完成后就关闭数据库连接。频繁的数据库连接对象的申请与释放,导致大量的资源耗费在了数据库连接创建与释放上面,而第三方的orm框架则采用了数据库连接池的办法,极大的优化了数据库连接的频繁申请与释放操作:需要进行数据库操作时,从数据库连接池中获取一个可用连接;不用时将连接返还给连接池;而连接池维护着每一个数据库连接的连接生命周期,只要还在数据库连接还在生命周期内,那么这个数据库连接就不会断开。

java数据库连接池的图示展示

java-web-7.2

java数据库连接池的实现思路

java数据库连接池在jdk中已经有相关的接口了——java.sql.DataSource;但是如果我们要手动实现一个数据库连接池的时候,应该怎么去做?数据库连接池最重要的是实现池的作用——成为数据库连接对象的容器以及管理容器内的所有数据库连接对象;实现当数据库连接断开时,连接对象不是被直接回收,而是重新回到容器中(这是最难的点);容器的话,可以采用线程安全的java.util.Vector来充当。而对象的重新回收到容器当中,可以利用java的代理机制来实现——实现数据库连接对象的代理。

java数据库连接池代码实现

1
2
3
4
5
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.0:3306/jdbcpool
jdbc.username=root
jdbc.password=xxxx
jdbc.poolsize=10
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
import javax.sql.DataSource;
import java.io.PrintWriter;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.Vector;
import java.util.logging.Logger;

public class MyDataSource implements DataSource {

private static Vector<Connection> connections = new Vector<>();

/**
* 静态代码区,通过properties文件获取相关数据库配置信息
*/
static {
InputStream in = MyDataSource.class.getClassLoader().getResourceAsStream("myDB.properties");
Properties properties = new Properties();
try {
properties.load(in);
String driver = properties.getProperty("jdbc.driver");
String url = properties.getProperty("jdbc.url");
String username = properties.getProperty("jdbc.username");
String password = properties.getProperty("jdbc.password");
int poolsize = Integer.valueOf(properties.getProperty("jdbc.poolsize"));
Class.forName(driver);
for (int i = 0; i < poolsize; i ++) {
Connection connection = DriverManager.getConnection(url, username, password);
System.out.println("success get connection");
connections.addElement(connection);
}
} catch (SQLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}

@Override
public Connection getConnection() throws SQLException {
if (connections.size()>0) {
//从Connections集合中获取一个数据库连接
final Connection conn = connections.remove(0);
System.out.println("jdbc pool size is :" + connections.size());
//返回Connection对象的代理对象
return (Connection) Proxy.newProxyInstance(MyDataSource.class.getClassLoader(), conn.getClass().getInterfaces(), new InvocationHandler(){
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if(!method.getName().equals("close")){
return method.invoke(conn, args);
}else{
//如果调用的是Connection对象的close方法,就把conn还给数据库连接池
connections.addElement(conn);
System.out.println(conn + "return to jdbc pool");
System.out.println("jdbc pool size is" + connections.size());
return null;
}
}
});
}else {
throw new RuntimeException("busy");
}
}

@Override
public Connection getConnection(String username, String password) throws SQLException {
return null;
}

@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
return null;
}

@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return false;
}

@Override
public PrintWriter getLogWriter() throws SQLException {
return null;
}

@Override
public void setLogWriter(PrintWriter out) throws SQLException {

}

@Override
public void setLoginTimeout(int seconds) throws SQLException {

}

@Override
public int getLoginTimeout() throws SQLException {
return 0;
}

@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return null;
}
}

数据库连接池测试(picture)

数据库连接池测试-运行结果展示

数据库连接池测试(Video)

bilibili video by Mynameis蠢逼