Servlet的JDBC 数据库连接池

时间:2020-12-06 11:49:35
国庆的最后的时候,花了些时间整理下笔记等东东:(一些乱乱的东西)

纯servlet的demo中使用的;
JDBC 数据库连接池:(代码测试不能用,不过思路应该是对的,后来改好的  代码不对 没有返回    下面的代码是可用的)
首先,需要一个继承 DataSource接口的类,这个就是地址池了;
改写里面的 Connection  getConnection()方法(无参的),这个是用来分配地址的,代码可以这么写,大概这样:
   
   
   
public Connection getConnection() throws SQLException {
//给线程方法连接
synchronized (pool) {
if(pool.size()>0){//容器里有东东
return pool.remove();//给一个出去
}else if (pool.size()==0&&count<maxPoolSize) {
pool.add(createConnection());
return pool.remove();
}else {
//容器没有连接了,并且连接数已经超过最大值,让线程等。
try {
pool.wait();//让线程等待
} catch (InterruptedException e) {
// TODO: handle exception
e.printStackTrace();
}
return pool.remove();
}
}
//return null;
}
这里的pool就是一个容器,里面就是连接池咯!

然后,在这个类里要有创建连接数据库的方法: Connection createConnection();
不过这里面的地址(放到地址池里的是代理过的连接):
   
   
   
//专门创建连接
private Connection createConnection(){
Connection conn =null;
try {
Class.forName(driverClassName);
conn=DriverManager.getConnection(url, user, password);
//上面是正常的连接!!
//下面是对连接进行代理,为了就是在调用close方法时 不调用真正的close方法
//而是我们自己写 的 连接 回收的 方法 代码
CloseMethodHandler handler = new CloseMethodHandler(pool);
Connection proxyconnConnection = handler.createProxy(conn);
count=count+1;
//return conn;
return proxyconnConnection;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
当然 ,这里对这个地址池 类的构造方法 还是要写一下  ,要在构造的时候 先获得基本的数据 并创建 几个连接到地址池
   
   
   
private LinkedList<Connection> pool=new LinkedList<Connection>();
private String driverClassName;
private String url;
private String user;
private String password;
private int count=0;//连接计数
public MyDataSource(int maxPoolSize,int initPoolSize,String driverClassName,String url,String user,String password){
this.initPoolSize=initPoolSize;
this.maxPoolSize=maxPoolSize;
this.driverClassName=driverClassName;
this.url=url;
this.user=user;
this.password=password;
//创建三个连接
for (int i = 0; i < initPoolSize; i++) {
Connection conn =createConnection();
pool.add(conn);
}
}
这构造方法就没什么好说明的 了:
接下来:​要创建上面的 CloseMethodHandler这个类了,这个类是用来创建 代理的;
也就是,代理原本正真的数据库连接,以便在其调用close方法时,调用回收 和 线程 唤醒;

这个类必须继承 InvocationHandler这个接口,并重写 invoke(Object proxy, Method method, Object[] args)方法;
这个方法就是用来处理(拦截)代理对象方法使用的;
   
   
   
public class CloseMethodHandler implements InvocationHandler {
private Connection target;
private LinkedList<Connection> pool;
//构造方法 是因为需要pool对象而创建的
public CloseMethodHandler(LinkedList<Connection> pool){
this.pool=pool;
}
//target是被代理对象,创建一个代理对象//用来创建一个代理的对象 ,并将参数的真的对象 保存起来先  
/*不过我感觉这里有问题,对参数的处理不太对的赶脚*/
public Connection createProxy(Connection target){
System.out.println(target.getClass().getName());
this.target=target;
//这个就是一个创建 代理 的方法 参数 我也弄的不明白 好像是 源对象的实例化的方式 ,代理对象的类型(接口),实现代理的类(就是自己)
                    /*感觉这个也有问题 对参数就是搞不明白*/
return (Connection) Proxy.newProxyInstance(target.getClass().getClassLoader(), new Class[]{Connection.class}, this);
}
//拦截被代理对象的方法的方法==》拦截Connection对象中close的方法。
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if(method.getName().equals("close")){
//拦截
synchronized (pool) {
pool.add((Connection) proxy);
pool.notify();//唤醒等待的线程
}
}else{
    return method.invoke(target, args);//不拦截 //如果这个不返回 则所有的方法 都返回空
}//问题就是在这里了,这个原先没有返回 所以所有的方法都被拦截了
return null; //这里是不能返回空 close方法是返回空 而其他的方法 是有 返回的
}
}
至于,这个地址池的使用,就很方便了,只要 创建一个这个地址池的单例,调动里面的方法来获得数据库的连接就可以了;;

数据库连接池:(小结)
管理多个数据库连接的容器-连接池。
特点:
里面有多个连接。
这些连接一般不关闭。
负责分发和回收。
把Connection 的 close 改造成释放连接,并且唤醒等待的线程。
使用代理:完成方法的改造
替代Connection的 close方法。
第三方成熟的数据库连接池:C3P0,DBCP。
自定义数据库连接:
1、实现javax.sql.DataSource接口。
2、重写里面一个getConnection()方法
3、设置一个连接数的最大值。(保护数据库)
4、设置一个初始化的连接数。
5、负责回收。(连接不关闭,而是回到数据库连接池,并变为空闲状态。)。
6、设置线程等待和解锁的机制。

当然这里使用第三方的开源插件是最好的,有:c3p0- 和 commons-pool -dbcp  这两个常用的;这里就试了下c3p0 是可以用的,另外一个似乎有版本问题!!!!我写的demo有问题应该,,,