spring源码解读之 JdbcTemplate源码

    在Spring中,JdbcTemplate是经常被使用的类来帮助用户程序操作数据库,在JdbcTemplate为用户程序提供了许多便利的数据库操作方法,比如查询,更新等,而且在Spring中,有许多类似 JdbcTemplate的模板,比如HibernateTemplate等等 - 看来这是Rod.Johnson的惯用手法,

    所谓模板板式,就是在父类中定义算法的主要流程,而把一些个性化的步骤延迟到子类中去实现,父类始终控制着整个流程的主动权,子类只是辅助父类实现某些可定制的步骤。 

我们用代码来说话吧: 
首先,父类要是个抽象类: 

Java代码   收藏代码
  1. public abstract class TemplatePattern {  
  2.   
  3.     //模板方法  
  4.     public final void templateMethod(){  
  5.           
  6.         method1();  
  7.         method2();//勾子方法  
  8.         method3();//抽象方法  
  9.     }  
  10.     private void method1(){  
  11.         System.out.println("父类实现业务逻辑");  
  12.     }  
  13.     public void method2(){  
  14.         System.out.println("父类默认实现,子类可覆盖");  
  15.     }  
  16.     protected abstract void method3();//子类负责实现业务逻辑  
  17. }  


父类中有三个方法,分别是method1(),method2()和method3()。 
method1()是私有方法,有且只能由父类实现逻辑,由于方法是private的,所以只能父类调用。 
method2()是所谓的勾子方法。父类提供默认实现,如果子类觉得有必要定制,则可以覆盖父类的默认实现。 
method3()是子类必须实现的方法,即制定的步骤。 
由此可看出,算法的流程执行顺序是由父类掌控的,子类只能配合。 

下面我们来写第一个子类: 

Java代码   收藏代码
  1. public class TemplatePatternImpl extends TemplatePattern {  
  2.   
  3.     @Override  
  4.     protected void method3() {  
  5.         System.out.println("method3()在子类TemplatePatternImpl中实现了!!");  
  6.   
  7.     }  
  8.   
  9. }  

这个子类只覆盖了必须覆盖的方法,我们来测试一下: 
Java代码   收藏代码
  1. TemplatePattern t1 = new TemplatePatternImpl();  
  2. t1.templateMethod();  

在控制台中我们可以看到: 
Java代码   收藏代码
  1. 父类实现业务逻辑  
  2. 父类默认实现,子类可覆盖  
  3. method3()在子类TemplatePatternImpl中实现了!!  


OK,我们来看看勾子方法的使用: 
定义第2个子类,实现勾子方法: 

Java代码   收藏代码
  1. public class TemplatePatternImpl2 extends TemplatePattern {  
  2.   
  3.     @Override  
  4.     protected void method3() {  
  5.         System.out.println("method3()在子类TemplatePatternImpl2中实现了!!");  
  6.   
  7.     }  
  8.   
  9.     /* (non-Javadoc) 
  10.      * @see com.jak.pattern.template.example.TemplatePattern#method2() 
  11.      */  
  12.     @Override  
  13.     public void method2() {  
  14.         System.out.println("子类TemplatePatternImpl2覆盖了父类的method2()方法!!");  
  15.     }  
  16.       
  17. }  


来测试一下: 
Java代码   收藏代码
  1. TemplatePattern t2 = new TemplatePatternImpl2();  
  2. t2.templateMethod();  

我们看控制台: 
Java代码   收藏代码
  1. 父类实现业务逻辑  
  2. 子类TemplatePatternImpl2覆盖了父类的method2()方法!!  
  3. method3()在子类TemplatePatternImpl2中实现了!!  


OK,经典的模板模式回顾完了(大家不要拍砖哦~~~~~~~~~~) 

接下来,我们回到正题,自己模仿spring动手写一个基于模板模式和回调的jdbcTemplate。 

回顾一下,spring为什么要封装JDBC API,对外提供jdbcTemplate呢(不要仍鸡蛋啊¥·%¥#%) 
话说SUN的JDBC API也算是经典了,曾经在某个年代折服了一批人。但随着历史的发展,纯粹的JDBC API已经过于底层,而且不易控制,由开发人员直接接触JDBC API,会造成不可预知的风险。还有,数据连接缓存池的发展,也不可能让开发人员去手工获取JDBC了。 

好了,我们来看一段曾经堪称经典的JDBC API代码吧: 

Java代码   收藏代码
  1. public List<User> query() {  
  2.   
  3.     List<User> userList = new ArrayList<User>();  
  4.     String sql = "select * from User";  
  5.   
  6.     Connection con = null;  
  7.     PreparedStatement pst = null;  
  8.     ResultSet rs = null;  
  9.     try {  
  10.         con = HsqldbUtil.getConnection();  
  11.         pst = con.prepareStatement(sql);  
  12.         rs = pst.executeQuery();  
  13.   
  14.         User user = null;  
  15.         while (rs.next()) {  
  16.   
  17.             user = new User();  
  18.             user.setId(rs.getInt("id"));  
  19.             user.setUserName(rs.getString("user_name"));  
  20.             user.setBirth(rs.getDate("birth"));  
  21.             user.setCreateDate(rs.getDate("create_date"));  
  22.             userList.add(user);  
  23.         }  
  24.   
  25.   
  26.     } catch (SQLException e) {  
  27.         e.printStackTrace();  
  28.     }finally{  
  29.         if(rs != null){  
  30.             try {  
  31.                 rs.close();  
  32.             } catch (SQLException e) {  
  33.                 e.printStackTrace();  
  34.             }  
  35.         }  
  36.         try {  
  37.             pst.close();  
  38.         } catch (SQLException e) {  
  39.             e.printStackTrace();  
  40.         }  
  41.         try {  
  42.             if(!con.isClosed()){  
  43.                 try {  
  44.                     con.close();  
  45.                 } catch (SQLException e) {  
  46.                     e.printStackTrace();  
  47.                 }  
  48.             }  
  49.         } catch (SQLException e) {  
  50.             e.printStackTrace();  
  51.         }  
  52.           
  53.     }  
  54.     return userList;  
  55. }  


上面的代码要若干年前可能是一段十分经典的,还可能被作为example被推广。但时过境迁,倘若哪位程序员现在再在自己的程序中出现以上代码,不是说明该公司的开发框架管理混乱,就说明这位程序员水平太“高”了。 
我们试想,一个简单的查询,就要做这么一大堆事情,而且还要处理异常,我们不防来梳理一下: 
1、获取connection 
2、获取statement 
3、获取resultset 
4、遍历resultset并封装成集合 
5、依次关闭connection,statement,resultset,而且还要考虑各种异常 
6、..... 
啊~~~~ 我快要晕了,在面向对象编程的年代里,这样的代码简直不能上人容忍。试想,上面我们只是做了一张表的查询,如果我们要做第2张表,第3张表呢,又是一堆重复的代码: 
1、获取connection 
2、获取statement 
3、获取resultset 
4、遍历resultset并封装成集合 
5、依次关闭connection,statement,resultset,而且还要考虑各种异常 
6、..... 

这时候,使用模板模式的时机到了!!! 

通过观察我们发现上面步骤中大多数都是重复的,可复用的,只有在遍历ResultSet并封装成集合的这一步骤是可定制的,因为每张表都映射不同的java bean。这部分代码是没有办法复用的,只能定制。那就让我们用一个抽象的父类把它们封装一下吧: 

Java代码   收藏代码
  1. public abstract class JdbcTemplate {  
  2.   
  3.     //template method  
  4.     public final Object execute(String sql) throws SQLException{  
  5.           
  6.         Connection con = HsqldbUtil.getConnection();  
  7.         Statement stmt = null;  
  8.         try {  
  9.    
  10.             stmt = con.createStatement();  
  11.             ResultSet rs = stmt.executeQuery(sql);  
  12.             Object result = doInStatement(rs);//abstract method   
  13.             return result;  
  14.         }  
  15.         catch (SQLException ex) {  
  16.              ex.printStackTrace();  
  17.              throw ex;  
  18.         }  
  19.         finally {  
  20.    
  21.             try {  
  22.                 stmt.close();  
  23.             } catch (SQLException e) {  
  24.                 e.printStackTrace();  
  25.             }  
  26.             try {  
  27.                 if(!con.isClosed()){  
  28.                     try {  
  29.                         con.close();  
  30.                     } catch (SQLException e) {  
  31.                         e.printStackTrace();  
  32.                     }  
  33.                 }  
  34.             } catch (SQLException e) {  
  35.                 e.printStackTrace();  
  36.             }  
  37.               
  38.         }  
  39.     }  
  40.       
  41.     //implements in subclass  
  42.     protected abstract Object doInStatement(ResultSet rs);  
  43. }  

在上面这个抽象类中,封装了SUN JDBC API的主要流程,而遍历ResultSet这一步骤则放到抽象方法doInStatement()中,由子类负责实现。 
好,我们来定义一个子类,并继承上面的父类: 

Java代码   收藏代码
  1. public class JdbcTemplateUserImpl extends JdbcTemplate {  
  2.   
  3.     @Override  
  4.     protected Object doInStatement(ResultSet rs) {  
  5.         List<User> userList = new ArrayList<User>();  
  6.           
  7.         try {  
  8.             User user = null;  
  9.             while (rs.next()) {  
  10.   
  11.                 user = new User();  
  12.                 user.setId(rs.getInt("id"));  
  13.                 user.setUserName(rs.getString("user_name"));  
  14.                 user.setBirth(rs.getDate("birth"));  
  15.                 user.setCreateDate(rs.getDate("create_date"));  
  16.                 userList.add(user);  
  17.             }  
  18.             return userList;  
  19.         } catch (SQLException e) {  
  20.             e.printStackTrace();  
  21.             return null;  
  22.         }  
  23.     }  
  24.   
  25. }  

由代码可见,我们在doInStatement()方法中,对ResultSet进行了遍历,最后并返回。 
有人可能要问:我如何获取ResultSet 并传给doInStatement()方法啊??呵呵,问这个问题的大多是新手。因为此方法不是由子类调用的,而是由父类调用,并把ResultSet传递给子类的。我们来看一下测试代码: 

Java代码   收藏代码
  1. String sql = "select * from User";  
  2. JdbcTemplate jt = new JdbcTemplateUserImpl();  
  3. List<User> userList = (List<User>) jt.execute(sql);  


就是这么简单!! 

文章至此仿佛告一段落,莫急!不防让我们更深入一些... 

试想,如果我每次用jdbcTemplate时,都要继承一下上面的父类,是不是有些不方面呢? 
那就让我们甩掉abstract这顶帽子吧,这时,就该callback(回调)上场了 


所谓回调,就是方法参数中传递一个接口,父类在调用此方法时,必须调用方法中传递的接口的实现类。 

那我们就来把上面的代码改造一下,改用回调实现吧: 

首先,我们来定义一个回调接口: 

Java代码   收藏代码
  1. public interface StatementCallback {  
  2.     Object doInStatement(Statement stmt) throws SQLException;  
  3. }  


这时候,我们就要方法的签名改一下了: 
Java代码   收藏代码
  1. private final Object execute(StatementCallback action) throws SQLException  


里面的获取数据方式也要做如下修改: 
Java代码   收藏代码
  1. Object result = action.doInStatement(stmt);//abstract method   


为了看着顺眼,我们来给他封装一层吧: 
Java代码   收藏代码
  1. public Object query(StatementCallback stmt) throws SQLException{  
  2.     return execute(stmt);  
  3. }  


OK,大功告成! 
我们来写一个测试类Test.java测试一下吧: 
这时候,访问有两种方式,一种是内部类的方式,一种是匿名方式。 

先来看看内部类的方式: 

Java代码   收藏代码
  1. //内部类方式  
  2.     public Object query(final String sql) throws SQLException {  
  3.         class QueryStatementCallback implements StatementCallback {  
  4.   
  5.             public Object doInStatement(Statement stmt) throws SQLException {  
  6.                 ResultSet rs = stmt.executeQuery(sql);  
  7.                 List<User> userList = new ArrayList<User>();  
  8.   
  9.                 User user = null;  
  10.                 while (rs.next()) {  
  11.   
  12.                     user = new User();  
  13.                     user.setId(rs.getInt("id"));  
  14.                     user.setUserName(rs.getString("user_name"));  
  15.                     user.setBirth(rs.getDate("birth"));  
  16.                     user.setCreateDate(rs.getDate("create_date"));  
  17.                     userList.add(user);  
  18.                 }  
  19.                 return userList;  
  20.   
  21.             }  
  22.   
  23.         }  
  24.   
  25.         JdbcTemplate jt = new JdbcTemplate();  
  26.         return jt.query(new QueryStatementCallback());  
  27.     }  


在调用jdbcTemplate.query()方法时,传一个StatementCallBack()的实例过去,也就是我们的内部类。 

再来看看匿名方式: 

Java代码   收藏代码
  1. //匿名类方式  
  2.     public Object query2(final String sql) throws Exception{  
  3.           
  4.         JdbcTemplate jt = new JdbcTemplate();  
  5.         return jt.query(new StatementCallback() {  
  6.               
  7.             public Object doInStatement(Statement stmt) throws SQLException {  
  8.                 ResultSet rs = stmt.executeQuery(sql);  
  9.                 List<User> userList = new ArrayList<User>();  
  10.   
  11.                 User user = null;  
  12.                 while (rs.next()) {  
  13.   
  14.                     user = new User();  
  15.                     user.setId(rs.getInt("id"));  
  16.                     user.setUserName(rs.getString("user_name"));  
  17.                     user.setBirth(rs.getDate("birth"));  
  18.                     user.setCreateDate(rs.getDate("create_date"));  
  19.                     userList.add(user);  
  20.                 }  
  21.                 return userList;  
  22.   
  23.             }  
  24.         });  
  25.           
  26.     }  

相比之下,这种方法更为简洁。 
为什么spring不用传统的模板方法,而加之以Callback进行配合呢? 

试想,如果父类中有10个抽象方法,而继承它的所有子类则要将这10个抽象方法全部实现,子类显得非常臃肿。而有时候某个子类只需要定制父类中的某一个方法该怎么办呢?这个时候就要用到Callback回调了。 

    最后的源码为:

package com.jak.pattern.template.callbacktemplate;
import java.sql.SQLException;
import java.sql.Statement;
//<span style="font-family: Helvetica, Tahoma, Arial, sans-serif; font-size: 14px; line-height: 25.200000762939453px;">回调接口</span>
public interface StatementCallback {
	Object doInStatement(Statement stmt) throws SQLException;
}


public class JdbcTemplate {
	//template method
	private final Object execute(StatementCallback action) throws SQLException{	
		Connection con = HsqldbUtil.getConnection();
		Statement stmt = null;
		try {
			stmt = con.createStatement();
			Object result = action.doInStatement(stmt);//abstract method 
			return result;
		}
		catch (SQLException ex) {
			 ex.printStackTrace();
			 throw ex;
		}
		finally {
			try {
				stmt.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			try {
				if(!con.isClosed()){
					try {
						con.close();
					} catch (SQLException e) {
						e.printStackTrace();
					}
				}
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
}
 
	public Object query(StatementCallback stmt) throws SQLException{
		
		 
		return execute(stmt);
	}
}
//调用测试类
public class Test {
	
	//内部类方式
	public Object query(final String sql) throws SQLException {
		class QueryStatementCallback implements StatementCallback {

			public Object doInStatement(Statement stmt) throws SQLException {
				ResultSet rs = stmt.executeQuery(sql);
				List<User> userList = new ArrayList<User>();

				User user = null;
				while (rs.next()) {

					user = new User();
					user.setId(rs.getInt("id"));
					user.setUserName(rs.getString("user_name"));
					user.setBirth(rs.getDate("birth"));
					user.setCreateDate(rs.getDate("create_date"));
					userList.add(user);
				}
				return userList;

			}

		}

		JdbcTemplate jt = new JdbcTemplate();
		return jt.query(new QueryStatementCallback());
	}

	//匿名类方式
	public Object query2(final String sql) throws Exception{
		
		JdbcTemplate jt = new JdbcTemplate();
		return jt.query(new StatementCallback() {
			
			public Object doInStatement(Statement stmt) throws SQLException {
				ResultSet rs = stmt.executeQuery(sql);
				List<User> userList = new ArrayList<User>();

				User user = null;
				while (rs.next()) {

					user = new User();
					user.setId(rs.getInt("id"));
					user.setUserName(rs.getString("user_name"));
					user.setBirth(rs.getDate("birth"));
					user.setCreateDate(rs.getDate("create_date"));
					userList.add(user);
				}
				return userList;

			}
		});
		
	}
	public static void main(String[] args) throws Exception {

		String sql = "select * from User";
		Test t = new Test();
		
		List<User> userList = (List<User>) t.query(sql);
		List<User> userList2 = (List<User>) t.query2(sql);
		System.out.println(userList);
		System.out.println(userList2);
	}
}


言归正传,有了上面的基础后,我们正式开始阅读源码:

下面几个接口是对变化的部分进行建模

接口:创建PreparedStatement。根据Connection来创建PreparedStatement。
 
  1. public interface PreparedStatementCreator {  
  2.      PreparedStatement createPreparedStatement (Connection conn)  
  3.        throws SQLException;  
  4.    }  

    使用方法就是:
 
  1. PreparedStatementCreator psc = new PreparedStatementCreator() {  
  2.   
  3.      public PreparedStatement createPreparedStatement (Connection conn)  
  4.          throws SQLException {  
  5.        PreparedStatement ps = conn. prepareStatement (  
  6.          "SELECT seat_id AS id FROM available_seats WHERE " +  
  7.          "performance_id = ? AND price_band_id = ?");  
  8.        ps.setInt(1, performanceId);  
  9.        ps.setInt(2, seatType);  
  10.        return ps;  
  11.      }  
  12.    };  

给PreparedStatement设置参数。是对PreparedStatmentCreator的设置ps值的一个补充。
  1. public interface PreparedStatementSetter {  
  2.     void setValues(PreparedStatement ps) throws SQLException;  
  3. }  
      
对ResultSet进行处理。还有具体的子类。
 
  1. public interface RowCallbackHandler {  
  2.      void processRow(ResultSet rs) throws SQLException;  
  3.    }  

       使用方式:
 
  1.  RowCallbackHandler rch = new RowCallbackHandler() {  
  2.    public void processRow(ResultSet rs) throws SQLException {  
  3.      int seatId = rs.getInt(1) ;  
  4.      list.add(new Integer (seatId) );//典型的inner class的应用,list为外部类的变量。    
  5.    }  
  6.  };  
和上面的RowCallbackHandler类似。
 
  1. public interface ResultSetExtractor {    
  2.       Object extractData(ResultSet rs) throws SQLException, DataAccessException;    
  3. }   
      下面是JdbcTemplate中提供的模板方法。该方法完成对数据库的查询:)。
       这个execute()方法非常关键。
 
  1. public Object query(  
  2.             PreparedStatementCreator psc, final PreparedStatementSetter pss, final ResultSetExtractor rse)  
  3.             throws DataAccessException {  
  4.   
  5.         Assert.notNull(rse, "ResultSetExtractor must not be null");  
  6.   
  7.         if (logger.isDebugEnabled()) {  
  8.             String sql = getSql(psc); //取得不变的SQL部分。 
  9.             logger.debug("Executing SQL query" + (sql != null ? " [" + sql  + "]" : ""));  
  10.         }  
  11.         return execute(psc, new PreparedStatementCallback() {  
  12.             public Object doInPreparedStatement(PreparedStatement ps) throws SQLException {  
  13.                 ResultSet rs = null;  
  14.                 try {  
  15.                     if (pss != null) {  
  16.                         pss.setValues(ps);//就是给ps来设置参数用的。ps.setInt(1, 0);  
  17.                     }  
  18.   
  19.                     rs = ps.executeQuery();//执行查询  
  20.   
  21.                     ResultSet rsToUse = rs;  
  22.                     if (nativeJdbcExtractor != null) {  
  23.                         rsToUse = nativeJdbcExtractor.getNativeResultSet(rs);  
  24.                     }  
  25.                     return rse.extractData(rsToUse); // ResultSetExtractor从ResultSet中将值取出List。  
  26.   
  27.                 }  
  28.                 finally {  
  29.                     //最后的善后工作还是需要做好的:) rs.close(),把ps的相关参数清除掉。  
  30.                     JdbcUtils.closeResultSet(rs);  
  31.                     if (pss instanceof ParameterDisposer) {  
  32.                         ((ParameterDisposer) pss).cleanupParameters();  
  33.                     }  
  34.                 }  
  35.             }  
  36.         });  
  37.     }  

看看execute()方法吧。

java 代码
 
  1. public Object execute(PreparedStatementCreator psc, PreparedStatementCallback action)  
  2.             throws DataAccessException {  
  3.   
  4.         Assert.notNull(psc, "PreparedStatementCreator must not be null");  
  5.         Assert.notNull(action, "Callback object must not be null");  
  6.   
  7.         //取得数据库的连接  
  8.         Connection con = DataSourceUtils.getConnection(getDataSource());  
  9.         PreparedStatement ps = null;  
  10.         try {  
  11.             Connection conToUse = con;  
  12.             if (this.nativeJdbcExtractor != null &&  
  13.                     this.nativeJdbcExtractor.isNativeConnectionNecessaryForNativePreparedStatements()) {  
  14.                 conToUse = this.nativeJdbcExtractor.getNativeConnection(con);  
  15.             }  
  16.             //创建PreparedStatement  
  17.             ps = psc.createPreparedStatement(conToUse);  
  18.   
  19.             applyStatementSettings(ps);//这个方法是设置ps的一些属性,我平时不用,Spring框架倒是考虑得相当全的说。  
  20.               
  21.             PreparedStatement psToUse = ps;  
  22.             if (this.nativeJdbcExtractor != null) {  
  23.                 psToUse = this.nativeJdbcExtractor.getNativePreparedStatement(ps);  
  24.             }  
  25.             //调用Callback来完成PreparedStatement的设值。就是调用上面的doInPreparedStatement来使用ps。  
  26.             Object result = action.doInPreparedStatement(psToUse);  
  27.             
  28.             SQLWarning warning = ps.getWarnings();  
  29.             throwExceptionOnWarningIfNotIgnoringWarnings(warning);  
  30.             return result;  
  31.         }  
  32.         //如果有错误的话,那么就开始ps.close(), connection.close();  
  33.         catch (SQLException ex) {  
  34.             // Release Connection early, to avoid potential connection pool deadlock  
  35.             // in the case when the exception translator hasn't been initialized yet.  
  36.             if (psc instanceof ParameterDisposer) {  
  37.                 ((ParameterDisposer) psc).cleanupParameters();  
  38.             }  
  39.             String sql = getSql(psc);  
  40.             psc = null;  
  41.             JdbcUtils.closeStatement(ps);  //就是ps.close();
  42.             ps = null;  
  43.             DataSourceUtils.releaseConnection(con, getDataSource()); /  
  44.             con = null;  
  45.             throw getExceptionTranslator().translate("PreparedStatementCallback", sql, ex);  
  46.         }  
  47.         //不管怎么样,ps.close(), Connection.close()吧,当然这里是releaseConnection。在我的程序中,Connection只有一个,没有ConnectionPool,当然不会去close Connection。一般来讲,如果没有Connection的线程池的话,我们肯定也不会经常的关闭Connection,得到Connection。毕竟这个东西非常耗费资源。  
  48.         finally {  
  49.             if (psc instanceof ParameterDisposer) {  
  50.                 ((ParameterDisposer) psc).cleanupParameters();  
  51.             }  
  52.             JdbcUtils.closeStatement(ps);  
  53.             DataSourceUtils.releaseConnection(con, getDataSource());  
  54.         }  
  55.     }  

JdbcTemplate完成了负责的操作,客户只需要调用query()就可以完成查询操作了。当然,JdbcTemplate会实现很多带其它参数的方法,以方便你的使用。Template设计模式被发扬广大了。

DataSourceUtils:这个专门用于管理数据库Connection的类。

 
  1. public static Connection getConnection(DataSource dataSource) throws CannotGetJdbcConnectionException {  
  2.         try {  
  3.             return doGetConnection(dataSource);  
  4.                 ~~~~~~ //这个方法很舒服,Spring Framework中到处有这样的方法。为什么要委派到这个动作方法?  
  5.         }  
  6.         catch (SQLException ex) {  
  7.             throw new CannotGetJdbcConnectionException("Could not get JDBC Connection", ex);  
  8.         }  
  9.     }  

    这里的doGetConnection就稍微复杂一点了。但是如果没有事务同步管理器的话,那就比较简单。
只是在Connection上多了一个ConnecionHolder类用于持有Connection,实现ConnectionPool的一点小功能。
 
  1. public static Connection doGetConnection(DataSource dataSource) throws SQLException {  
  2.         Assert.notNull(dataSource, "No DataSource specified");  
  3.   
  4.         ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);  
  5.         ~~~~~//Connection的持有器。通过持有器得到Connection。
  6.         if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {  
  7.             conHolder.requested();  
  8.             if (!conHolder.hasConnection()) {  
  9.                 logger.debug("Fetching resumed JDBC Connection from DataSource");  
  10.                 conHolder.setConnection(dataSource.getConnection());  
  11.             }  
  12.             return conHolder.getConnection();  
  13.         }  
  14.         // Else we either got no holder or an empty thread-bound holder here.  
  15.   
  16.         logger.debug("Fetching JDBC Connection from DataSource");  
  17.         Connection con = dataSource.getConnection();   
  18.         ……
  19.         return con;  
  20.     }  

ConnectionHolder:Connection的持有器。通过ConnectionHandler来完成对Connection的操作:) 典型的委派。
 
  1. public class ConnectionHolder extends ResourceHolderSupport {  
  2.       
  3.     private Connection currentConnection; //当前的Connection  
  4.     private ConnectionHandle connectionHandle;  //Connection的处理器,因此可以通过该类完成对connection的管理。  
  5.   
  6.     public ConnectionHolder(Connection connection) {  
  7.         this.connectionHandle = new SimpleConnectionHandle(connection);  
  8.     }  
  9.       
  10.     public ConnectionHolder(ConnectionHandle connectionHandle) {  
  11.         Assert.notNull(connectionHandle, "ConnectionHandle must not be null");  
  12.         this.connectionHandle = connectionHandle;  
  13.     }  
  14.   
  15.     public Connection getConnection() {  
  16.         Assert.notNull(this.connectionHandle, "Active Connection is required");  
  17.         if (this.currentConnection == null) {  
  18.             this.currentConnection = this.connectionHandle.getConnection();  
  19.         }  
  20.         return this.currentConnection;  
  21.     }  
  22.   
  23.     public void released() {  
  24.         super.released();  
  25.         if (this.currentConnection != null) {  
  26.             this.connectionHandle.releaseConnection(this.currentConnection);  
  27.             this.currentConnection = null;  
  28.         }  
  29.     }  

connectionHandle 的接口太纯粹了。但是我觉得这个设计太过于细致了:) 
 
  1. public interface ConnectionHandle {  
  2.   
  3.     /** 
  4.      * Fetch the JDBC Connection that this handle refers to. 
  5.      */  
  6.     Connection getConnection();  
  7.   
  8.     /** 
  9.      * Release the JDBC Connection that this handle refers to. 
  10.      * @param con the JDBC Connection to release 
  11.      */  
  12.     void releaseConnection(Connection con);  
  13.   
  14. }  

  最后看一下SimpleConnectionHandle,这个ConnectionHandle的简单实现类。就只有一个Connection可管理。如果有多个Connection可管理的话,这里就是ConnectionPool了:)

java 代码
 
  1. public class SimpleConnectionHandle implements ConnectionHandle {  
  2.   
  3.     private final Connection connection;  
  4.   
  5.   
  6.     /** 
  7.      * Create a new SimpleConnectionHandle for the given Connection. 
  8.      * @param connection the JDBC Connection 
  9.      */  
  10.     public SimpleConnectionHandle(Connection connection) {  
  11.         Assert.notNull(connection, "Connection must not be null");  
  12.         this.connection = connection;  
  13.     }  
  14.   
  15.     /** 
  16.      * Return the specified Connection as-is. 
  17.      */  
  18.     public Connection getConnection() {  
  19.         return connection;  
  20.     }  
  21.   
  22.     /** 
  23.      * This implementation is empty, as we're using a standard 
  24.      * Connection handle that does not have to be released. 
  25.      */  
  26.     public void releaseConnection(Connection con) {  
  27.     }  
  28.   
  29.   
  30.     public String toString() {  
  31.         return "SimpleConnectionHandle: " + this.connection;  
  32.     }  
  33.   
  34. }  

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值