`

传智播客李勇Jdbc视频笔记(34-42)

阅读更多
34、编写一个基本的连接池来实现连接的复用
大家都知道Arraylist的底层使用数组实现的,而LinkedList使用链表实现的,所以对于Arraylist读取速度比较快而对于LinkedList修改和添加
比较快,所以我们这个连接池因为要频繁的操作集合所以用LinkedList来实现。
public class MyDataSource {
		private static String url = "jdbc:mysql://localhost:3306/jdbc?generateSimpleParameterMetadata=true";
		private static String user = "root";
		private static String password = "admin";
		
		LinkedList<Connection> connectionsPool = new LinkedList<Connection>();
		
		//向我们的LinkedList集合中加入10个链接作为我们的连接池
		public MyDataSource() {
			for(int i=0; i<10; i++) {
				try {
					//将Connection放到链表的最后面
					connectionsPool.addLast(this.createConnection());
				} catch (SQLException e) {
					throw new ExceptionInInitializerError(e.getMessage());
				}
			}
		}
		//创建10个链接
		public Connection createConnection() throws SQLException{
			return DriverManager.getConnection(url, user, password);
		}
		
		//得到一个链接(先进先出算法)
		public Connection getConnection() {
			return connectionsPool.removeFirst();
		}
		
		//关闭一个链接,这个关闭不是真正意义上的关闭,而是又把他放回到连接池中,实现了Connection的复用
		public void free(Connection conn) {
			connectionsPool.addLast(conn);
		}
	}


35、对基本连接池进行一些工程细节上的优化
在上面实现的连接池中我们只是默认创建了5个连接,但是如果这个时候有5个线程同时都来拿连接,那连接池里就没有连接
在有线程过来拿的时候就会报错了,现在我们进行一些优化(重复的代码就不写了,只写改动的)
//规定默认创建的连接数
	private static int initCount = 5;
	//规定最大可以创建的连接数
	private static int maxCount = 10;
	//统计当前共创建了多少个连接
	private int currentCount = 0;
	
	LinkedList<Connection> connectionsPool = new LinkedList<Connection>();
	
	public MyDataSource() {
		for(int i=0; i<initCount; i++) {
			try {
				connectionsPool.addLast(this.createConnection());
				//每创建一个链接 currentCount ++
				this.currentCount ++;
			} catch (SQLException e) {
				throw new ExceptionInInitializerError(e.getMessage());
			}
		}
	}
	
	public Connection createConnection() throws SQLException{
		return DriverManager.getConnection(url, user, password);
	}
	
	public Connection getConnection() throws SQLException {
		//因为Connection不是线程安全的,所以我必须保证每个线程拿到的链接不是一个,所以要进行同步:当两个线程同时来拿的时候
		//另外一个线程必须等待
		synchronized (connectionsPool) {
			if(connectionsPool.size() > 0)
				return connectionsPool.removeFirst();
			//如果当前创建的链接数没有到最大值,那就继续创建链接
			if(this.currentCount < maxCount) {
				this.currentCount ++;
				return this.createConnection();
			}
			//抛出异常
			throw new SQLException("当前已经没有可用连接了");
		}
	}


36、通过代理模式来保持用户关闭连接的习惯.
在上面的示例中我们在关闭链接的时候,调用的是free方法来把这个连接又放回到了池中,但是按照开发人员的使用习惯应该是调用colse()方法
来关闭一个链接,但是如果调用close方法关闭,那这个连接就真的关闭了,也就是说我们这个方法设计的不符合开发人员的使用习惯下面我用代理的
方法来解决这个问题:
定义一个类实现Connection接口,Connectio接口中有很多的方法,这些方法我们都无法自己完成,我们交给通过构造方法传递进来的真正的Connection
的对象来完成,我们只是修改它的close方法,在用户得到链接的时候我们返回给用户这个类的对象,那么当用户调用close方法关闭链接的时候,我们就可以在
这个close方法中将用户要关闭的那个链接再次的放到连接池中,这样链接就不会真正的关闭了。
public class MyConnection implements Connection {
	
	MyDataSource2 dataSource;
	Connection realConn;
	int maxUseCount = 5;
	int currentUseCount = 0;
	
	MyConnection(MyDataSource2 myDataSource2, Connection conn) {
		this.dataSource = myDataSource2;
		this.realConn = conn;
	}
	
	public void clearWarnings() throws SQLException {
		realConn.clearWarnings();
	}

	public void close() throws SQLException {
		this.currentUseCount++;
		//规定同一个链接只能使用maxUseCount次超过这个次数,就把真正的链接关闭,这个时候在拿连接,拿到的就是
		新创建得一个新的链接对象了。
		if (this.currentUseCount < this.maxUseCount) {
			this.dataSource.connectionsPool.addLast(this);
		}
		else {
			this.realConn.close();
			this.dataSource.currentCount--;
		}
	}

	public void commit() throws SQLException {
		this.realConn.commit();
	}
	
	
	在类MyDataSource中我们别的都不改变,只改变他的一个方法(MyDataSource的全部代码查看34)
	当用户想拿到链接的时候返回给他conn类的一个代理对象myConnection对象就可
	public Connection createConnection() throws SQLException{
		Connection conn = DriverManager.getConnection(url, user, password);
		MyConnection myConnection = new MyConnection(this, conn);
		return myConnection;
	}


37、Java的动态代理及使用该技术完善连接代理
在上面的示例中,我们为了产生一个代理对象实现了Connection接口的所有的方法,但是我们只需要修改它的close方法,别的方法
我们都需要交给真正的Connection对象去处理,比较麻烦我们用动态代理来实现它

public class MyConnectionHandler implements InvocationHandler {
	
		private Connection conn;
		private MyDataSource2 dataSource;
		private int maxUseCount = 5;
		private int currentUseCount = 0;
		private Connection proxyConn;
		
		MyConnectionHandler(MyDataSource2 dataSource) {
			this.dataSource = dataSource;
		}
		
		Connection bind(Connection realConnection) {
			this.conn = realConnection;
			//生成Connection的代理对象
			proxyConn = (Connection)Proxy.newProxyInstance(Connection.class.getClassLoader(), new Class[]{Connection.class}, this);
			//System.out.println(proxyConn + "代理");
			return proxyConn;
		}
		
		public Object invoke(Object proxy, Method method, Object[] args)
				throws Throwable {
			//调用方法的时候如果是close方法就执行我们的逻辑,对于其他的所有的方法,全部交给真实Connection对象本身自己去处理
			if("close".equals(method.getName())) {
				this.currentUseCount ++;
				if(this.currentUseCount < this.maxUseCount) {
					this.dataSource.free(proxyConn);
				}
				else {
					this.conn.close();
					this.dataSource.currentCount --;
				}
			}
			return method.invoke(conn, args);
		}
	}


当写完上面的代理类后,我们还是需要修改MyDataSource类的createConnection()方法来调用我们的代理类,将它需要的参数
传递给他并把生成的代理类返回:
public Connection createConnection() throws SQLException{
		Connection conn = DriverManager.getConnection(url, user, password);
		MyConnectionHandler proxyConn = new MyConnectionHandler(this);
		return proxyConn.bind(conn);
	}


38、标准DataSource接口及数据源的总结介绍
理解数据源的优势与特点:
DataSource用来取代DriverManager来获取Connection;
通过DataSource获得Connection速度很快;
通过DataSource获得的Connection都是已经被包裹过的(不是驱动原来的连接),他的close方法已经被修改。
一般DataSource内部会用一个连接池来缓存Connection,这样可以大幅度提高数据库的访问速度;
连接池可以理解成一个能够存放Connection的Collection;
我们的程序只和DataSource打交道,不会直接访问连接池;

39、如何使用开源项目DBCP(实际项目中常用):主要分为三个步骤
(1)使用DBCP必须用的三个包:commons-dbcp-1.2.1.jar, commons-pool-1.2.jar, commons-collections-3.1.jar。
(2)添加dbcp的配置文件
(3)Java API: BasicDataSourceFactory.createDataSource(properties);

在我们上面的示例中我们的MyDataSource可以实现Datasource接口,实现里面的getConnection()方法,我们想用dbcp的时候,把
数据源的实现换成dbcp就行,因为这个组件也实现了DataSource接口,所以这就是面向接口编程的好处,可以换成不同的实现 ,不用
改变我们其他的代码

40、将DAO中的修改方法提取到抽象父类中:
当你在写程序的时候,如果你发现你的代码总是有重复的地方那么就有必要封装一下了。把一段代码中的变化的部分
抽取到父类里,把要用的参数传递过去,然后再实现类里面直接super调用父类的方法就可以了。把参数传递过去就行了
可以向外提过多个方法的重载 但是真正的代码实现只有一份。

41、使用模板方法设计模式处理DAO中的查询方法
在这个示例中需要用到多态的知识一般我们说满足多态要有三个条件:
(1)要有继承
(2)要有方法的重写
(3)要有父类的引用指向子类对象
但是有一种情况是特殊的:如果子类调用父类的方法(包括构造方法)而在你调用的这个父类的方法里你又调用了父类中的其他的方法,而你调用的这个
方法又被子类重写了,那么这就是多态

简单的程序示例:
抽象类
public abstract class AbstractDao {
		abstract public String printName(String name) ;
		public String test2() {
			this.printName("aaa");
			return "你好";
		}
	}
	
	//调用抽象类的方法
	public class AbstractDaoImpl1 extends AbstractDao {

		public void getName() {
			super.test2();

		}

		@Override
		public String printName(String name) {
			return null;
		}
	}


我们用一个抽象类把重复的方法封装到里面,那么多个类都实现了父类的方法,在调用的时候我们怎么知道调用的是哪个
实现方法呢,这个时候Java的多态特性就发挥作用了:你在实现类中调用父类的方法,而你重写了你要调用的这个方法,那么
你调用的就是你自己实现的这个方法。
把相同的代码抽取出来封装成为一个方法,把容易变动的地方作为方法的参数传递进去 ,这样我们的Dao层会省去很多的重复的代码
而这个封装的方法就可以称之为“模板方法”

42、使用策略模式对模板方法设计模式进行改进
sql1 = "select name from user where id = ?";
sql2 = "select id, name, age from user where id = ?";
这两个sql查询的对象不一样,一个是只需要返回一个name属性的值就可以,而另外一个sql需要返回一个User
对象,这样的话我们上面的模板方法就有不好用了,虽然可以查出来但是性能上有损失 我只要查询一个username
你可能会把整个User对象都给我查询出来。我们可以针对每个不同的sql语句查询的内容的不同把模板方法也分解成
多个不一样的能满足相应sql查询语句的方法,这就叫做策略模式,就是针对每一种情况都有不同的方法,来解决
//行映射器
	public interface RowMapper {
		public Object mapRow(ResultSet rs) throws SQLException;
	}
	//对于方法的封装
	public class MyDaoTemplate {
		public Object find(String sql, Object[] args, RowMapper rowMapper) {
			Connection conn = null;
			PreparedStatement ps = null;
			ResultSet rs = null;
			try {
				conn = JdbcUtils.getConnection();
				ps = conn.prepareStatement(sql);
				for (int i = 0; i < args.length; i++)
					ps.setObject(i + 1, args[i]);
				rs = ps.executeQuery();
				Object obj = null;
				if (rs.next()) {
					obj = rowMapper.mapRow(rs);
				}
				return obj;
			} catch (SQLException e) {
				throw new DaoException(e.getMessage(), e);
			} finally {
				JdbcUtils.free(rs, ps, conn);
			}
		}
	}

//对于下面的不同的sql,在我们调用find方法的时候new RowMapper然后针对不同的sql有不同的实现就可以了
//JdbcTemplete也为我们封装了这个方法。
	MyDaoTemplate template = new MyDaoTemplate();
	public String findUserName(int id) {
		String sql = "select name from user where id=?";
		Object[] args = new Object[] { id };
		Object name = this.template.find(sql, args, new RowMapper() {

			public Object mapRow(ResultSet rs) throws SQLException {
				return rs.getString("name");
			}
		});
		return (String) name;
	}
	
分享到:
评论
1 楼 lovegong 2010-11-11  
您好
请教一个问题
37、Java的动态代理及使用该技术完善连接代理
        public Object invoke(Object proxy, Method method, Object[] args) 
                throws Throwable { 
            //调用方法的时候如果是close方法就执行我们的逻辑,对于其他的所有的方法,全部交给真实Connection对象本身自己去处理 
            if("close".equals(method.getName())) { 
                this.currentUseCount ++; 
                if(this.currentUseCount < this.maxUseCount) { 
                    this.dataSource.free(proxyConn); 
                } 
                else { 
                    this.conn.close(); 
                    this.dataSource.currentCount --; 
                } 
            } 
            return method.invoke(conn, args); 
        } 
关于这段代码,我想问下当调用close方法时 if语句执行完成后  return method.invoke(conn, args); 执行的是conn.close()么?如果是那就真的关掉了,如果不是那执行的是什么样的语句,我很疑惑。对invoke的执行过程不是很熟
谢谢

相关推荐

    传智播客 李勇老师 JDBC代码全部和ppt

    【标题】"传智播客 李勇老师 JDBC代码全部和ppt" 提供的是一个关于JDBC编程的全面学习资源,由知名教育机构传智播客的讲师李勇主讲。JDBC(Java Database Connectivity)是Java编程语言中用于与各种数据库进行交互的...

    传智播客-Jdbc-李勇.ppt

    传智播客-Jdbc-李勇.ppt 传智播客-Jdbc-李勇.ppt 传智播客-Jdbc-李勇.ppt

    传智播客李勇hibernate源码1-20课

    传智播客李勇hibernate源码1-20课,目录如下:01_hibernate介绍与动手入门体验;02_hibernate入门案例的细节分析; 03_hibernate入门案例的代码优化; 04_Session接口及get|load|persist方法 05_实体对象的三种状态...

    传智播客李勇hibernate PPT

    【传智播客李勇hibernate PPT】是一份由知名教育机构传智播客推出的关于Hibernate框架的培训资料,由讲师李勇精心制作。这份PPT详细讲解了Hibernate在实际开发中的应用,旨在帮助学员深入理解并掌握这一强大的Java...

    传智播客_hibernate李勇笔记

    传智播客_hibernate李勇笔记是在学习李勇老师讲的hibernate3.2.5后整理的笔记

    hibernate_传智播客_李勇

    hibernate_传智播客_李勇

    传智播客李勇hibernate

    【传智播客李勇hibernate】课程详解了ORM框架Hibernate的核心概念和技术,适合初学者和想要深入了解Hibernate的开发者。以下是对课程内容的详细解析: 1. **引入ORM框架**: - 阻抗不匹配:由于Java是面向对象的...

    hibernate传智播客李勇ppt

    传智播客hibernate讲解视频配套ppt,李勇

    传智播客 李勇 hibernate 的ppt

    【传智播客 李勇 Hibernate 讲解】 在IT领域,ORM(Object-Relational Mapping,对象关系映射)框架是将面向对象的模型与关系数据库之间进行映射的关键技术,有效地解决了“模型不匹配”(也称为“阻抗不匹配”)的...

    传智播客JDBC_所有源码与ppt

    本资源“传智播客JDBC_所有源码与ppt”是针对JDBC学习的一个综合包,包含了源代码和相关的教学演示PPT,非常适合初学者或希望深入理解JDBC的开发者使用。传智播客是一家知名的教育机构,其课程内容通常具有系统性和...

    传智播客 hibernate PPT 很经典

    传智播客 hibernate PPT 很经典

    JDBC笔记 李勇

    **JDBC笔记 李勇** JDBC(Java Database Connectivity)是Java编程语言中用来规范应用程序如何访问数据库的应用程序编程接口,提供了诸如连接数据库、发送SQL语句、处理结果集等功能。李勇老师的JDBC学习笔记主要...

    传智播客SSHppt

    - **传智播客李勇hibernate**:李勇老师的Hibernate课程可能包括了Hibernate的基本原理、实体类与表的映射、CRUD操作、查询语言(HQL)、Criteria查询、级联操作、缓存策略等。他可能强调了如何优雅地处理数据库操作...

    传智播客SSH三大框架的PPT

    在IT行业中,SSH三大框架是Java Web开发领域中不可或缺的一部分...这些PPT资源,如"传智播客李勇hibernate.ppt"、"spring.ppt"、"struts2.ppt",提供了详细的讲解和示例,对学习SSH框架的开发者来说是一份宝贵的资料。

    传智播客Java培训ppt大全

    本Java培训资料集合了多位知名讲师的精华内容,包括比向东、方力勋、黎活明、张孝祥、杨忠科、李勇、韩顺平等,覆盖了Java的基础到高级知识点,旨在帮助学习者全面掌握Java编程。 1. **Java基础** - **语法基础**...

Global site tag (gtag.js) - Google Analytics