使用动态代理实现一个简单的数据库连接池

明确一点:数据库连接是一个重量级的对象,每一个连接的建立是一个复杂且很消耗资源的事情。为了复用已经创建好的连接,出现了池技术。连接池、线程池、对象池等等。这里采用动态代理实现一个简单的数据库连接池。

代码

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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import java.io.InputStream;
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.DriverManager;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.LinkedList;
import java.util.Properties;
import java.util.logging.Logger;
import javax.sql.DataSource;
public class JdbcPool implements DataSource {
//使用LinkedList集合,会使用到大量的增删改查
private static LinkedList<Connection> list = new LinkedList<Connection>();
static{
try{
//读取数据库连接的必要配置
InputStream in = JdbcPool.class.getClassLoader().getResourceAsStream("db.properties");
Properties prop = new Properties();
prop.load(in);
String driver= prop.getProperty("driver");
String url = prop.getProperty("url");
String username = prop.getProperty("username");
String password = prop.getProperty("password");
//加载驱动
Class.forName(driver);
//找数据要多少个链接,就循环多少次
for(int i=0;i<10;i++){
Connection conn = DriverManager.getConnection(url, username, password);
//把链接存入集合中
System.out.println("获取到了链接:"+conn);
list.add(conn);
}
}catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
}
/*
1.写一个子类,覆盖close方法
2.写一个Connection的包装类,增强close方法
3.用动态代理,返回一个代理对象出去,拦截close方法的调用,对close方法进行增强
*/
public Connection getConnection() throws SQLException {
//proxyConnection.commit() proxyConnection.rollback
if(list.size()>0){
final Connection conn = list.removeFirst(); //myconnection.commit
System.out.println("池大小是:" + list.size());
//使用动态代理
return (Connection) Proxy.newProxyInstance(
JdbcPool.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{
list.add(conn);
System.out.println(conn + "被还给池了!!");
System.out.println("池大小为" + list.size());
return null;
}
}
});
}else{
throw new RuntimeException("对不起,数据库忙");
}
}
@Override
public PrintWriter getLogWriter() throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public void setLogWriter(PrintWriter out) throws SQLException {
// TODO Auto-generated method stub
}
@Override
public void setLoginTimeout(int seconds) throws SQLException {
// TODO Auto-generated method stub
}
@Override
public int getLoginTimeout() throws SQLException {
// TODO Auto-generated method stub
return 0;
}
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
// TODO Auto-generated method stub
return null;
}
@Override
public <T> T unwrap(Class<T> iface) throws SQLException {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
// TODO Auto-generated method stub
return false;
}
@Override
public Connection getConnection(String username, String password)
throws SQLException {
// TODO Auto-generated method stub
return null;
}
}

原理

DataSource接口是必须要实现的,上面那些未实现的方法这里不做说明,都是DataSource接口中需要实现的方法。JdbcPool在加载进内存时候,就已经找数据库获取了10个数据库连接。getConnection()获取数据库连接,返回的就是Connection的一个代理对象出去。最终要做的事情是,拦截对close()方法的处理,当发现调用的是close()方法时,并不去执行释放连接,而是把连接返回到了LinkedList集合里面去了。

谢谢你请我吃糖果

--------- 本文结束,感谢您的审阅 ---------
0%