黑马day11 动态代理&模拟一个数据库连接池

数据库连接池:说白了就是在一个池子中(容器)中放了很多的数据库连接,当用户需要的时候就从中取出来一个用,用完了就放回连接池中。

优点:极大的提高了数据库的效率。

对于自定义的数据库连接池我们使用一个LinkedList做数据库连接池.这个集合的特点是增删快,查询慢。

自定义一个数据库连接池的步骤:

1.自定义一个类实现DataSource接口。

2.定义一个List<Connection> list=new LinkedList<Connection>();存放数据库连接。

3.初始化数据库连接池。就是在静态代码块static块中添加数据库的连接若干到list中(连接池)。

4.写一个方法returnPool(Connection con)还回到数据库连接池。如果数据库连接池中没有数据连接可用,就添加若干个带数据库连接池list中。

5.在getConnection()方法中动态代理重新改造Connection的close方法,因为我们不能够用完了就关闭,而是应该用完了还回数据库连接池中。这样可以循环使用。

案例:

自定义自己的数据库连接池MyPool

package com.itheima.mypools;

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.List;
import java.util.logging.Logger;

import javax.sql.DataSource;

public class MyPool implements DataSource{
	//1.需要一个容器存放连接
	private static List<Connection> list=new LinkedList<Connection>();
	//初始化加载类的时候就在连接池中添加了5个连接
	static{
		try {
			//2.加载驱动
			Class.forName("com.mysql.jdbc.Driver");
			for(int i=0;i<5;i++){
				//3.获取连接
				Connection con=DriverManager.getConnection("jdbc:mysql://localhost:3306/day11", "root", "169500");
				list.add(con);
			}
		}catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException();
		}
	}
	@Override
	public Connection getConnection() throws SQLException {
		//如果连接池的数据没有了就添加3个连接到连接池中
		if(list.size()==0){
			for(int i=0;i<3;i++){
				Connection con=DriverManager.getConnection("jdbc:mysql://localhost:3306/day11", "root", "169500");
				list.add(con);
			}
		}
		//获取连接,就是把连接池中的连接remove不是get...
		final Connection con = list.remove(0);

		//需要重写连接的close()方法,我们使用动态代理
		Connection proxy=(Connection) Proxy.newProxyInstance(con.getClass().getClassLoader(), con.getClass().getInterfaces(), new InvocationHandler() {
			@Override
			public Object invoke(Object proxy, Method method, Object[] args)//proxy代理类对象 method被代理类的方法,args被代理类方法的参数
					throws Throwable {
				if("close".equals(method.getName())){
					//要改造的方法就还回连接池
					returnPool(con);
					return null;
				}else{
					//不想改造的方法就使用被代理者对象的方法
					return method.invoke(con, args);
				}
			}
		});
		System.out.println("获取了一个连接,连接池中还有:"+list.size()+"个连接");
		return proxy;
	}
	public void returnPool(Connection con){
		try {
			if(con!=null&&!con.isClosed()){
				list.add(con);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		System.out.println("还回了一个连接,池里还剩余"+list.size()+"个连接");
	}
	@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;
	}

}

使用这个自己定义的数据库连接池:

package com.itheima.mypools;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import cn.itheima.utils.JDBCUtils;

public class JDBCDemo1 {
	public static void main(String[] args) {
		Connection con=null;
		PreparedStatement ps=null;
		ResultSet rs=null;
		try {
			//使用数据库连接池
			MyPool pool=new MyPool();
			//获取连接
			con=pool.getConnection();
			ps=con.prepareStatement("select * from account");
			rs=ps.executeQuery();
			while(rs.next()){
				String name=rs.getString("name");
				System.out.println(name);
			}
		} catch (SQLException e) {
			e.printStackTrace();
			throw new RuntimeException();
		}finally{
			//这里的close已经被更该过了
			if(rs!=null){
				try {
					rs.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}finally{
					rs=null;
				}
			}
			if(ps!=null){
				try {
					ps.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}finally{
					ps=null;
				}
			}
			if(con!=null){
				try {
					con.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}finally{
					con=null;
				}
			}
		}

	}
}

运行结果:

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-12-17 04:28:58

黑马day11 动态代理&模拟一个数据库连接池的相关文章

关于利用动态代理手写数据库连接池的异常 java.lang.ClassCastException: com.sun.proxy.$Proxy0 cannot be cast to java.sql.Connection

代码如下: final Connection conn=pool.remove(0); //利用动态代理改造close方法 Connection proxy= (Connection) Proxy.newProxyInstance(conn.getClass().getClassLoader(), conn.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object pro

【设计模式】动态代理 &amp;&amp; 模拟JDK动态代理

真正理解动态代理需要明白回答以下问题: 什么叫动态代理?怎么产生? 动态代理的作用?可配置的事务,权限控制,日志等等....只有你想不到,没有动态代理做不到. 下面来回答以上3个问题: 先说下静态代理: 方法:创建代理类,代理类包含被代理对象的方法并在被代理方法的前后加添加的方法. 创建代理类可以用继承接口或者聚合(implements)被代理对象的接口来实现,然后传入被代理对象的实例.其中聚合并继承好,使用继承的时候如果代理类需要嵌套代理类或者创建不同的代理类,需要创建不同的代理类.造成类泛滥

自定义一个数据库连接池

package com.huawei.datasource; import java.sql.Array;import java.sql.Blob;import java.sql.CallableStatement;import java.sql.Clob;import java.sql.Connection;import java.sql.DatabaseMetaData;import java.sql.NClob;import java.sql.PreparedStatement;impor

黑马程序员——java——模拟一个字符串中的trim方法去掉一个字符串两端的空格

模拟一个字符串中的trim方法去掉一个字符串两端的空格 public class StingTrimDemo { //模拟一个trim方法, 去掉一个字符串两边的空格], public static void main(String[] args) { // TODO Auto-generated method stub String s = " my java "; System.out.println("未去空格前的字符串+++:[ "+s+" ]&q

动态代理写connection连接池Demo

1 public class JdbcUtil2 { 2 //声明连接池<放到LinkedList中,操作其中对象的速度快 只需要改变连接> 3 private static LinkedList<Connection> connectionspool=new LinkedList<Connection>(); 4 //静态代码块 5 static{ 6 try { 7 String url="jdbc:mysql://localhost:3306/jdbcd

做一些Spring AOP做过的事,封装 jdk动态代理成为一个黑盒子

  怎么使用eclise 抽取方法,请看  利用eclipse 抽取代码片段为方法   抽取完成之后,还需要 ① 将Collection.class换成  target.getClass(),target是Object的,可以来代理所有的对象 ② Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHander(){     invo

总结代理模式 并根据数据库连接池原理来模拟实现自己的数据库连接池工具类

代理模式 需求:对系统中已有的某个类的功能,进行扩展(增强) 要求:在不修改源码的情况下,对已有的功能进行增强 静态代理 抽象接口:保证包含增强功能的对象和原有功能的对象,对外提供相同的方法 目标对象:封装了原有功能 代理对象:封装了增强功能和原有功能(通过持有一个目标对象的引用实现) 问题:代码不够灵活,产生大量冗余工作 动态代理 动态代理的实现API: Proxy : 帮助程员产生代理对象,提供产生代理类和代理对象的静态方法 InvocationHandler : 句柄接口,拦截到,所有代理

[javaEE] 数据库连接池和动态代理

实现javax.sql.DataSource接口 实现Connection getConnection()方法 定义一个静态的成员属性LinkedList类型作为连接池,在静态代码块中初始化5条数据库连接,添加到连接池中,在getConnection方法中,当获取连接的时候在连接池中remove掉一条连接就可以了 import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lan

使用Java中的动态代理实现数据库连接池

2002 年 12 月 05 日 作者通过使用JAVA中的动态代理实现数据库连接池,使使用者可以以普通的jdbc连接的使用习惯来使用连接池. 数据库连接池在编写应用服务是经常需要用到的模块,太过频繁的连接数据库对服务性能来讲是一个瓶颈,使用缓冲池技术可以来消除这个瓶颈.我们可以在 互联网上找到很多关于数据库连接池的源程序,但是都发现这样一个共同的问题:这些连接池的实现方法都不同程度地增加了与使用者之间的耦合度.很多的连接池 都要求用户通过其规定的方法获取数据库的连接,这一点我们可以理解,毕竟目前