博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
数据库连接池、动态代理
阅读量:6803 次
发布时间:2019-06-26

本文共 6049 字,大约阅读时间需要 20 分钟。

 

在web项目中,Java访问数据库采用的是多用户操作,需要频繁连接数据库,一种方法是来一个请求给一个操作对象,这种方法想法简单,但存在巨大隐患,如果访问量特别的大,数据库连接对象过多,可能导致奔溃。好的方法是,采用数据库连接时统一管理,包括数据库连接对象的个数限制以及使用后回收。

这里写图片描述

说到管理,根据程序员习惯,拿到连接对象进行完操作后,一般会关闭连接对象,这就会产生一个问题,下一次别的用户再拿到回收后的关闭对象后,由于对象已关闭,再进行其他操作的话,会产生异常。所以我们要修改close()这个函数的功能。

思路:要修改函数功能,基本上是采用覆盖的方法,一种方式是采用装饰模式,即继承加组合,但这种方式有个弊端,如果要实现的接口有很多函数,代码量非常大,所以一般不采用。另一种方式是采用代理模式。下面想详细叙述

代理要用到一个关键的API 类,即Proxy,此外要用到一个接口和接口的一个实例对象。 

Proxy.newProxyInstance(loader, interfaces, h); 
第一个参数:与被代理对象处于同一空间的类加载器 
第二个参数:要实现接口数组 
第三个参数:实现功能的句柄对象

下面是一个租房者通过中介租房的例子来演示:

接口

public interface IRenter {    public abstract void rent(int n);}

接口实现类

public class Renter implements IRenter{    @Override    public void rent(int n) {        System.out.println("给你"+n+"间房,请交500元钱");    }}
 

关键类

public class Client {    private static IRenter rent = new Renter();    public static void main(String[] args) {        Object obj = Proxy.newProxyInstance(Client.class.getClassLoader(), //                new Class[] { IRenter.class }, new InvocationHandler() {                    @Override                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {                        System.out.println("我代理的......");                        return method.invoke(rent, args);                    }                });        IRenter o = (IRenter) obj;        o.rent(3);    }}

 

 

根据原理。做一个代理工具类:

public class ProxyUtil implements InvocationHandler{ private Object srcObj; public ProxyUtil(Object srcObj) { super(); this.srcObj = srcObj; } public static Object getProxy(Object srcObj){ Object obj = Proxy.newProxyInstance( ProxyUtil.class.getClassLoader(), srcObj.getClass().getInterfaces(), new ProxyUtil(srcObj) ); return obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return method.invoke(srcObj, args); } }

 

 

数据库连接池的代码实现:

package me.gacl.demo;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.util.LinkedList;import java.util.Properties;import javax.sql.DataSource;/*** @ClassName: JdbcPool* @Description:编写数据库连接池* @author: 孤傲苍狼* @date: 2014-9-30 下午11:07:23**/ public class JdbcPool implements DataSource{    /**    * @Field: listConnections    *         使用LinkedList集合来存放数据库链接,    *        由于要频繁读写List集合,所以这里使用LinkedList存储数据库连接比较合适    */     private static LinkedList
listConnections = new LinkedList
(); static{ //在静态代码块中加载db.properties数据库配置文件 InputStream in = JdbcPool.class.getClassLoader().getResourceAsStream("db.properties"); Properties prop = new Properties(); try { prop.load(in); String driver = prop.getProperty("driver"); String url = prop.getProperty("url"); String username = prop.getProperty("username"); String password = prop.getProperty("password"); //数据库连接池的初始化连接数大小 int jdbcPoolInitSize =Integer.parseInt(prop.getProperty("jdbcPoolInitSize")); //加载数据库驱动 Class.forName(driver); for (int i = 0; i < jdbcPoolInitSize; i++) { Connection conn = DriverManager.getConnection(url, username, password); System.out.println("获取到了链接" + conn); //将获取到的数据库连接加入到listConnections集合中,listConnections集合此时就是一个存放了数据库连接的连接池 listConnections.add(conn); } } catch (Exception e) { throw new ExceptionInInitializerError(e); } } @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
T unwrap(Class
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; } /* 获取数据库连接 * @see javax.sql.DataSource#getConnection() */ @Override public Connection getConnection() throws SQLException { //如果数据库连接池中的连接对象的个数大于0 if (listConnections.size()>0) { //从listConnections集合中获取一个数据库连接 final Connection conn = listConnections.removeFirst(); System.out.println("listConnections数据库连接池大小是" + listConnections.size()); //返回Connection对象的代理对象 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{ //如果调用的是Connection对象的close方法,就把conn还给数据库连接池 listConnections.add(conn); System.out.println(conn + "被还给listConnections数据库连接池了!!"); System.out.println("listConnections数据库连接池大小为" + listConnections.size()); return null; } } }); }else { throw new RuntimeException("对不起,数据库忙"); } } @Override public Connection getConnection(String username, String password) throws SQLException { return null; }}

 

 

转载于:https://www.cnblogs.com/newlangwen/p/8017616.html

你可能感兴趣的文章
C# 视频监控系列(10):服务器端——验证、设置画面质量、字幕叠加、板卡序列号...
查看>>
ZAM 3D入门教程(1):初识ZAM 3D
查看>>
nagios安装
查看>>
idea springboot热部署无效问题
查看>>
ReentrantLock详解
查看>>
即时通讯之数字电视
查看>>
【C++实现有序子序列合并算法】
查看>>
防病毒插件更新失败!?
查看>>
HTTP的post和get总结
查看>>
CEPH Cache Tiering
查看>>
Oracle 11g新特性之--Server Result Cache
查看>>
Oracle中的ORA-01548: active rollback segment '_SYSSMU1$' found
查看>>
AngularJs $anchorScroll、$controller、$document
查看>>
Microsoft资源
查看>>
WordPress 永久链接或固定链接设置技巧
查看>>
数据结构之线性表
查看>>
在PPT中插入FLASH遇到的系列问题
查看>>
2015百度之星 下棋
查看>>
常用的CMD命令
查看>>
搭建网站必不可少的知识11
查看>>