代理实现连接池第三方连接池Dbutilsc3p0.docx
《代理实现连接池第三方连接池Dbutilsc3p0.docx》由会员分享,可在线阅读,更多相关《代理实现连接池第三方连接池Dbutilsc3p0.docx(23页珍藏版)》请在冰豆网上搜索。
代理实现连接池第三方连接池Dbutilsc3p0
代理实现连接池,第三方连接池,Dbutils
GenericServlet继承增强了HttpServlet(包装)
IO都是包装
BufferedReaderrd=newBufferedReader(newFileReader(“a.txt”));
BufferedReader增强了FileReader,从而可以由一个字符一个字符的读增强到可以到一行一行的读。
包装缺点:
1.需要实现的方法太多。
2.一个包装类,只可以包装一个被包装类。
如一个包装盒只可以包装一个蛋糕。
3.包装类也是被包装类(被包装的蛋糕,还是蛋糕)
对一个类增强的三种方式:
1.继承某个类extends
2.对某个类进行包装
3.动态代理
代理
代理的特点:
1.可以代理多个被代理类。
2.代理类不是被代理类,即经济人不是华仔。
3.代理可以在不污染任何类的情况下,对某个类进行代理。
代理的要求:
1.被代理的类必须要拥有一个接口。
2.代理的核心类:
●java.lang.reflect.Proxy–代理生成类
●java.lang.invokeHandler–执行句柄,可以在运行时获取正在调用某个方法,还有传递的参数
第一步:
如果要实现代理,某类必须要拥有一个接口。
Proxy(代理)在运行时根据给定的接口,在内存中创建一个与被代理类相同的类。
第二步:
示例代码
publicclassProxyDemo{
publicstaticvoidmain(String[]args){
System.err.println("1:
声明被代理类的实例");
finalCatcat=newCat();
System.err.println("2:
通过Proxy在内存中创建ICat的子类");
ObjectproxyedObj=Proxy.newProxyInstance(
ProxyDemo.class.getClassLoader(),newClass[]{Animal.class},
//拦截句柄,在执行时,只要执行代理类(经济人,中介-proxyedObj)任何方法,
//都会被这个句柄给拦截到
newInvocationHandler(){
//1:
参数:
proxy即proxyedObj,即这个一个代理,经济人,中介
//2:
Method即反射出来的代理对象的方法proxyedObj.getClass().getMethod(xx)
//3:
参数列表
publicObjectinvoke(Objectproxy,Methodmethod,
Object[]args)throwsThrowable{
System.err.println("5:
正在执行的方法为:
"+method.getName());
//如果没有返回则为null,调用cat对象的eat方法
ObjectreturnValue=method.invoke(cat,args);
System.err.println("7:
返回的值是:
"+returnValue);
returnreturnValue;
}
});
System.err.println("3:
将proxyedObj代理类,即经济人转成被代理对象");
Animala1=(Animal)proxyedObj;
System.err.println("4:
调用代理对象的(经济人的)eat方法");
a1.eat();
System.err.println("8:
执行完成");
}
}
//声明被代理类的class
interfaceAnimal{
publicvoideat();
}
classCatimplementsAnimal{
publicvoideat(){
System.err.println("6:
fishing...");
}
}
案例:
要求拦截List接口的添加元素方法。
分析:
即拦截List.add方法
/**
*拦截List添加方法
*/
publicclassInterListDemo{
publicstaticvoidmain(String[]args){
//1:
声明被代理的list
finalList
newArrayList
list.add("World");
//2:
在内存中创建List接口的子类
ObjectproxyedObj=
Proxy.newProxyInstance(InterListDemo.class.getClassLoader(),
newClass[]{List.class},
newInvocationHandler(){
publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)
throwsThrowable{
System.err.println("正在执行某个方法:
"+method.getName());
//判断是否是正在执行size方法
if(method.getName().equals("size")){
return100;
}else{//否则,即调用的不是size方法,直接去执行原对象的某个方法
ObjectreturnValue=method.invoke(list,args);
returnreturnValue;
}
}
});
//3:
转换
List
//list2.add("Hello");
//要求当调用size时不管原list中的size是多少,都返回100
System.err.println("list.size:
"+list2.size());
for(Objecto:
list2){
System.err.println(o);
}
}
}
代理实现连接池
用代理实现对Connection的close方法修改,目的要求不能关闭连接,应该是归还连接。
1.必须要有一个池,即List,LinkedList
2.创建多个连接入到List中去,在放之前,必须要对Connection进行代理
3.在代理的Connection方法中对所有其它方法都直接去调用原类即被代理类的方法,但对于close方法不能调用,应是修改为归还连接。
实现代码:
publicclassConnPool{
privatestaticLinkedListpool=
newLinkedList();
static{
try{
Propertiesp=
newProperties();
InputStreamin=
ConnPool.class.getClassLoader().getResourceAsStream("jdbc.properties");
p.load(in);
Stringdriver=p.getProperty("d");
Stringurl=p.getProperty("u");
Stringnm=p.getProperty("n");
Stringpwd=p.getProperty("p");
Integersize=Integer.valueOf(p.getProperty("s"));
//创建多个连接
for(inti=0;ifinalConnectioncon=//原生对象,即没有被代理的,但准备被代理的-华仔
DriverManager.getConnection(url,nm,pwd);
//声明代理类
ObjectconnProxy=
Proxy.newProxyInstance(
ConnPool.class.getClassLoader(),
newClass[]{Connection.class},
newInvocationHandler(){
publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)
throwsThrowable{
if(method.getName().equals("close")){
System.err.println("有人还连接了");
synchronized(pool){
//由于proxy就是connProxy,所以直接就将proxy添加回去就可以
pool.addLast((Connection)proxy);
pool.notify();
}
returnnull;
}else{
//如果调用的不是close方法则直接调用原生对象的方法即放行
returnmethod.invoke(con,args);
}
}
});
//将代理类,即经济人放到List中
pool.add((Connection)connProxy);
}
}catch(Exceptione){
e.printStackTrace();
}
}
publicstaticConnectiongetCon(){
synchronized(pool){
//计算时间的开始
longstart=System.currentTimeMillis();
while(pool.size()==0){
//进入等待池
System.err.println("取一次:
"+Thread.currentThread().getName());
try{
pool.wait(1000);
}catch(InterruptedExceptione){
e.printStackTrace();
}
//计算时间是否超过了三秒
longpro=System.currentTimeMillis()-start;
if(pro>3000){
System.err.println("已经超过3秒超时,放弃");
thrownewRuntimeException("时间超时了");
}
}
System.err.println(pool.size());
Connectioncon=pool.removeFirst();
returncon;
}
}
}
标准连接池
标准的连接池,就是实现DataSource接口,且实现DataSource接口的类,必须是具体类,没有静态方法。
ConnectiongetConnection()
AttemptstoestablishaconnectionwiththedatasourcethatthisDataSourceobjectrepresents.
尝试建立与此DataSource对象所表示的数据源的连接。
ConnectiongetConnection(Stringusername,Stringpassword)
AttemptstoestablishaconnectionwiththedatasourcethatthisDataSourceobjectrepresents.
尝试建立与此DataSource对象所表示的数据源的连接。
实现以上的两个方法:
1.基本实现–生成标准的Connection对象。
2.连接池实现–生成自动参与连接池的Connection对象。
此实现与中间层连接池管理器一起使用。
实现代码:
publicclassMyDataSourceimplementsDataSource{
//1:
声明池对象
privateLinkedListpool=
newLinkedList();
//2:
为了向pool中放connection必须要只,能通过构造初始化多个连接
publicMyDataSource(){
try{
Propertiesp=
newProperties();
InputStreamin=
MyDataSource.class.getClassLoader()
.getResourceAsStream("jdbc.properties");
p.load(in);
Stringdriver=p.getProperty("d");
Stringurl=p.getProperty("u");
Stringnm=p.getProperty("n");
Stringpwd=p.getProperty("p");
Integersize=Integer.valueOf(p.getProperty("s"));
//创建多个连接
for(inti=0;ifinalConnectioncon=//原生对象,即没有被代理的,但准备被代理的-华仔
DriverManager.getConnection(url,nm,pwd);
//声明代理类
ObjectconnProxy=
Proxy.newProxyInstance(
ConnPool.class.getClassLoader(),
newClass[]{Connection.class},
newInvocationHandler(){
publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)
throwsThrowable{
if(method.getName().equals("close")){
System.err.println("有人还连接了");
synchronized(pool){
//由于proxy就是connProxy,所以直接就将proxy添加回去就可以
pool.addLast((Connection)proxy);
pool.notify();
}
returnnull;
}else{
//如果调用的不是close方法则直接调用原生对象的方法即放行
returnmethod.invoke(con,args);
}
}
});
//将代理类,即经济人放到List中
pool.add((Connection)connProxy);
}
}catch(Exceptione){
e.printStackTrace();
}
}
publicConnectiongetConnection()throwsSQLException{
synchronized(pool){
//计算时间的开始
longstart=System.currentTimeMillis();
while(pool.size()==0){
//进入等待池
System.err.println("取一次:
"+Thread.currentThread().getName());
try{
pool.wait(1000);
}catch(InterruptedExceptione){
e.printStackTrace();
}
//计算时间是否超过了三秒
longpro=System.currentTimeMillis()-start;
if(pro>3000){
System.err.println("已经超过3秒超时,放弃");
thrownewRuntimeException("时间超时了");
}
}
System.err.println(pool.size());
Connectioncon=pool.removeFirst();
returncon;
}
}
如何使用:
通过第三方框架连接数据库
由于操作数据库,管理连接池,回收连接是JDBC必须要做的事,所以就有了第三方框架。
目前比较流行的连接池框架:
●dbcp-apache公司的dbcp=DataBaseConnectionPool版本1.2
●c3p0–0.9.1.2
●proxool–1.1
dbcp数据源
第一步:
导包
第二步:
dbcp核心类–声明一个类,用核心类连接数据库
BasicDataSource–它是javax.sql.DataSource子类。
对DataSource来说,它只是一个池,至于里面有没有连接,能不能连接到数据库,必须要通过dataSource.getConnection()测试。
如果只判断dataSource是否为null是不能确定是否连接数据库成功与否的。
c3p0数据源
c3p0的核心类:
ComboPooledDataSource–通过读取一个配置文件–配置文件必须是classpath:
c3p0-config.xml
第一步:
导包
第二步:
准备c3p0配置文件
第三步:
配置连接数据库的数据
xmlversion="1.0"encoding="UTF-8"?
>
--必须以c3p0-config开始-->
--在c3p0的配置文件中没有dtd定义-->
--必须要包含默认的配置项目-->
--配置驱动器-->
com.mysql.jdbc.Driver
[CDATA[jdbc:
mysql:
//127.0.0.1:
3306/day14?
useUnicode=true&characterEncoding=UTF-8]]>
root
1234
--初始化个数-->
2
--最少有多少个连接-->
2
--最多有多少个-->
4
--如果池中数据连接不够时一次增长多少个-->
3
--一个连接每一次最多执行多少个sql语句-->
50
第四步:
书写一个类,创建ComboPooledDataSource实例
publicclassDataSouceUtils{
//1:
声明ds的成员,一个项目中只要有一个ds就可以了
privatestaticDataSourceds;
//2:
在静态代码块中
static{
//如果直接实例化cpds则默认读取c3p0-config.xml中的默认配置
//如果带有参数,就会读取命名的配置
ds=newComboPooledDataSource();
}
//3:
提供一个静态方法返回ds实例
publicstaticDataSourcegetDataSource(){
returnds;
}
}
dbutils
定义
dbutils就是一个小型的hibenate。
就是将用户的CRUD工作都全部给封装了,用户通过简单的调用,就可以实现原来所有JDBC的一些功能。
(将statement.Query,execute,executeUpdate给封装了)
dbutils核心类
●QueryRunner,核心查询的类(select,update,delete,insert),相