今天中午吃饭时,听了公司架构师的一些话,意思是这样的:每天花一点时间看开源项目的源码,一开始看不懂没关系,继续看,即使看懂了3行代码,也是一种收获。来北京之后,自己也有一段时间看过一些项目的源码,但是断断续续的,一个项目看一点,那个项目看一点,没有形成整体的思维。现在重新开始看和整理,能看懂多少,就记录多少吧。
  
 
 
 
 
 
 
 
 
DbUtils is not: 
 
 
 
 
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
 
 
 
从这里,我们可以只是,相对于JDBC编程,AbstractQueryRunner已经帮我们封装了一下几步:
1、获得数据库连接
2、获得PreparedStatement
3、为PreparedStatement中的参数设置值 
4、关闭ResultSet、关闭PreparedStatement、关闭Connection 
这里缺少了最重要的一步,dbutils对于ResultSet怎样处理?这就要下次再说了。
PS:在这里讲一下 DbUtils中的close方法。在 AbstractQueryRunner的3个close方法中(关闭RS,关闭PS,关闭Connection)中就是调用了DbUtils中相对应的close方法。
  
    
 
 
  
  
  
  
  
    
                                                    
                                            
      
  
  
          第一次写阅读源码的笔记,先选了个较简单的dbutils。  
 
先来介绍下dbutils,去了官网弄了些文字过来。红色的那句看懂了,就大概知道dbutils是干什么的了。搞IT,英文很重要的,所以我不翻译了。看不懂的,还是去学习下英文吧。All right, let us get started !
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
Commons DbUtils: JDBC Utility Component
 
先来介绍下dbutils,去了官网弄了些文字过来。红色的那句看懂了,就大概知道dbutils是干什么的了。搞IT,英文很重要的,所以我不翻译了。看不懂的,还是去学习下英文吧。All right, let us get started !
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
Commons DbUtils: JDBC Utility Component
           
 The Commons DbUtils library is a small set of classes designed to make working with JDBC easier. 
  JDBC resource cleanup code is mundane, error prone work so these classes abstract out all of the cleanup tasks from your code leaving you with what you really wanted to do with JDBC in the first place: query and update data. 
 
 
 Some of the advantages of using DbUtils are: 
 
          (1)No possibility for resource leaks. Correct JDBC coding isn't difficult but it is time-consuming and tedious. This often leads to connection leaks that may be difficult to track down. 
 
          (2)Cleaner, clearer persistence code. The amount of code needed to persist data in a database is drastically reduced. The remaining code clearly expresses your intention without being cluttered with resource cleanup. 
 
          (3)Automatically populate JavaBean properties from ResultSets. You don't need to manually copy column values into bean instances by calling setter methods. Each row of the ResultSet can be represented by one fully populated bean instance. 
 
 
       Scope of the Package 
 
          DbUtils is designed to be: 
 
           
 Small 
  - you should be able to understand the whole package in a short amount of time. 
 
           
 Transparent 
  - DbUtils doesn't do any magic behind the scenes. You give it a query, it executes it and cleans up for you. 
 
           
 Fast 
  - You don't need to create a million temporary objects to work with DbUtils. 
 
DbUtils is not:
          (1)An Object/Relational bridge - there are plenty of good O/R tools already. DbUtils is for developers looking to use JDBC without all the mundane pieces. 
 
          (2)A Data Access Object (DAO) framework - DbUtils can be used to build a DAO framework though. 
 
          (3)An object oriented abstraction of general database objects like a Table, Column, or PrimaryKey. 
 
          (4)A heavyweight framework of any kind - the goal here is to be a straightforward and easy to use JDBC helper library. 
 
           
 Dependencies 
 
          DbUtils is intentionally a single jar distribution and relies only on a standard Java 1.6 or later JRE. 
   
 
 
  ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
 
 
  /* 
 
 
  
   * Licensed to the Apache Software Foundation (ASF) under one or more 
 
 
  
   * contributor license agreements.  See the NOTICE file distributed with 
 
 
  
   * this work for additional information regarding copyright ownership. 
 
 
  
   * The ASF licenses this file to You under the Apache License, Version 2.0 
 
 
  
   * (the "License"); you may not use this file except in compliance with 
 
 
  
   * the License.  You may obtain a copy of the License at 
 
 
  
   * 
 
 
  
  
   * 
 
 
  
   * Unless required by applicable law or agreed to in writing, software 
 
 
  
   * distributed under the License is distributed on an "AS IS" BASIS, 
 
 
  
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 
 
  
   * See the License for the specific language governing permissions and 
 
 
  
   * limitations under the License. 
 
 
  
   */ 
 
 
  
  package  
  org. 
  apache. 
  commons. 
  dbutils; 
 
 
  
  import  
  java. 
  beans. 
  IntrospectionException; 
 
 
  
  import  
  java. 
  beans. 
  Introspector; 
 
 
  
  import  
  java. 
  beans. 
  PropertyDescriptor; 
 
 
  
  import  
  java. 
  lang. 
  reflect. 
  InvocationTargetException; 
 
 
  
  import  
  java. 
  lang. 
  reflect. 
  Method; 
 
 
  
  import  
  java. 
  sql. 
  Connection; 
 
 
  
  import  
  java. 
  sql. 
  ParameterMetaData; 
 
 
  
  import  
  java. 
  sql. 
  PreparedStatement; 
 
 
  
  import  
  java. 
  sql. 
  ResultSet; 
 
 
  
  import  
  java. 
  sql. 
  SQLException; 
 
 
  
  import  
  java. 
  sql. 
  Statement; 
 
 
  
  import  
  java. 
  sql. 
  Types; 
 
 
  
  import  
  java. 
  util. 
  Arrays; 
 
 
  
  import  
  javax. 
  sql. 
  DataSource; 
 
 
  
  /** 
 
 
  
   * The base class for QueryRunner & AsyncQueryRunner. This class is thread safe. 
 
 
  
   * QueryRunner & AsyncQueryRunner的基础类:准备PreparedStatement、Connection、 
 
 
  
   * 填充PreparedStatement中的“?”占位符 
 
 
  
   * 关闭Connection、Statement、ResultSet 
 
 
  
  
   */ 
 
 
  
  public  
  abstract  
  class  
  AbstractQueryRunner { 
 
 
 
        
  /** 
 
 
  
  
       
   * it yet)? 
 
 
  
       
   * getParameterType(int)不可用吗? 
 
 
  
       
   */ 
 
 
 
        
  private  
  volatile  
  boolean  
  pmdKnownBroken  
  =  
  false; 
 
 
 
        
  /** 
 
 
  
       
   * The DataSource to retrieve connections from. 
 
 
  
       
   * 数据源,我们可以从此数据源中获得数据库连接。在使用dbutils时,要使用数据源。常用dbcp和c3p0 
 
 
  
  
       
   * 这里提示,要访问数据源,建议调用getDataSource()方法 
 
 
  
       
   */ 
 
 
 
       @ 
  Deprecated 
 
 
 
        
  protected  
  final  
  DataSource  
  ds; 
 
 
 
        
  /** 
 
 
  
       
   * Default constructor, sets pmdKnownBroken to false and ds to null. 
 
 
  
       
   * 默认构造函数中,设置数据源为null 
 
 
  
       
   */ 
 
 
 
        
  public  
  AbstractQueryRunner() { 
 
 
  
           
  ds  
  =  
  null; 
 
 
 
       } 
 
 
 
        
  /** 
 
 
  
       
   * Constructor to control the use of <code>ParameterMetaData</code>. 
 
 
  
       
   * 此构造器中控制了ParameterMetaData的使用,在使用中,个人比较少使用这种方式 
 
 
  
       
   *  
  @param 
   pmdKnownBroken 
 
 
  
       
   *            Some drivers don't support 
 
 
  
  
       
   *            <code>pmdKnownBroken</code> is set to true, we won't even try 
 
 
  
       
   *            it; if false, we'll try it, and if it breaks, we'll remember 
 
 
  
       
   *            not to use it again. 
 
 
  
       
   *            有一些驱动不支持getParameterType(int)。如果pmdKnownBroken设置为true,我们不会去尝试 
 
 
  
       
   *            ,如果为false,我们会尝试调用。如果不行,我们会记住不要再去调用它。 
 
 
  
       
   */ 
 
 
 
        
  public  
  AbstractQueryRunner( 
  boolean  
  pmdKnownBroken) { 
 
 
  
           
  this. 
  pmdKnownBroken  
  =  
  pmdKnownBroken; 
 
 
  
           
  //这里也设置了数据源为null 
 
 
  
           
  ds  
  =  
  null; 
 
 
 
       } 
 
 
 
        
  /** 
 
 
  
       
   * Constructor to provide a <code>DataSource</code>. Methods that do not 
 
 
  
       
   * take a <code>Connection</code> parameter will retrieve connections from 
 
 
  
       
   * this <code>DataSource</code>. 
 
 
  
       
   * 使用此构造器,可以为数据源赋值。没有Connection参数的方法将从此数据源中获得数据库连接。 
 
 
  
       
   * 在使用dbutils时,经常使用这个构造器 
 
 
  
       
   * 
 
 
  
       
   *  
  @param 
   ds 
 
 
  
       
   *            The <code>DataSource</code> to retrieve connections from. 
 
 
  
       
   */ 
 
 
 
        
  public  
  AbstractQueryRunner( 
  DataSource  
  ds) { 
 
 
  
           
  this. 
  ds  
  =  
  ds; 
 
 
 
       } 
 
 
 
        
  /** 
 
 
  
       
   * Constructor to provide a <code>DataSource</code> and control the use of 
 
 
  
       
   * <code>ParameterMetaData</code>. Methods that do not take a 
 
 
  
       
   * <code>Connection</code> parameter will retrieve connections from this 
 
 
  
       
   * <code>DataSource</code>. 
 
 
  
       
   * 这个就是上述两个的综合了,不多讲了 
 
 
  
       
   *  
  @param 
   ds 
 
 
  
       
   *            The <code>DataSource</code> to retrieve connections from. 
 
 
  
       
   *  
  @param 
   pmdKnownBroken 
 
 
  
       
   *            Some drivers don't support 
 
 
  
  
       
   *            <code>pmdKnownBroken</code> is set to true, we won't even try 
 
 
  
       
   *            it; if false, we'll try it, and if it breaks, we'll remember 
 
 
  
       
   *            not to use it again. 
 
 
  
       
   */ 
 
 
 
        
  public  
  AbstractQueryRunner( 
  DataSource  
  ds,  
  boolean  
  pmdKnownBroken) { 
 
 
  
           
  this. 
  pmdKnownBroken  
  =  
  pmdKnownBroken; 
 
 
  
           
  this. 
  ds  
  =  
  ds; 
 
 
 
       } 
 
 
 
        
  /** 
 
 
  
       
   * Returns the <code>DataSource</code> this runner is using. 
 
 
  
       
   * <code>QueryRunner</code> methods always call this method to get the 
 
 
  
       
   * <code>DataSource</code> so subclasses can provide specialized behavior. 
 
 
  
       
   * 这个是数据源属性的getter方法,上面建议访问数据源时,通过此方法进行访问 
 
 
  
  
       
   */ 
 
 
 
        
  public  
  DataSource  
  getDataSource() { 
 
 
  
           
  return  
  this. 
  ds; 
 
 
 
       } 
 
 
 
        
  /** 
 
 
  
       
   * Some drivers don't support 
 
 
  
  
       
   * <code>pmdKnownBroken</code> is set to true, we won't even try it; if 
 
 
  
       
   * false, we'll try it, and if it breaks, we'll remember not to use it 
 
 
  
       
   * again. 
 
 
  
       
   * 这个是pmdKnownBroken属性的getter方法,由于是boolean,可以使用isPmdKnownBroken 
 
 
  
  
  
  
       
   */ 
 
 
 
        
  public  
  boolean  
  isPmdKnownBroken() { 
 
 
  
           
  return  
  pmdKnownBroken; 
 
 
 
       } 
 
 
 
        
  /** 
 
 
  
       
   * Factory method that creates and initializes a 
 
 
  
       
   * <code>PreparedStatement</code> object for the given SQL. 
 
 
  
       
   * <code>QueryRunner</code> methods always call this method to prepare 
 
 
  
       
   * statements for them. Subclasses can override this method to provide 
 
 
  
       
   * special PreparedStatement configuration if needed. This implementation 
 
 
  
       
   * simply calls <code>conn.prepareStatement(sql)</code>. 
 
 
  
       
   * 工厂方法,为给定的SQL创建和实例化一个PreparedStatement对象。QueryRunner(AbstractQueryRunner的 
 
 
  
       
   * 子类)的方法总会调用此方法来准备statements。需要的话,子类可以覆盖此方法来提供特殊的PreparedStatement配置。 
 
 
  
       
   * 这里只是简单地调用了conn.prepareStatement(sql)。这是常见的JDBC,很容易明白。 
 
 
  
       
   *  
  @param 
   conn 
 
 
  
       
   *            The <code>Connection</code> used to create the 
 
 
  
       
   *            <code>PreparedStatement</code> 
 
 
  
       
   *  
  @param 
   sql 
 
 
  
       
   *            The SQL statement to prepare. 
 
 
  
  
  
       
   *             if a database access error occurs 
 
 
  
       
   */ 
 
 
 
        
  protected  
  PreparedStatement  
  prepareStatement( 
  Connection  
  conn,  
  String  
  sql) 
 
 
 
        
  throws  
  SQLException { 
 
 
  
           
  return  
  conn. 
  prepareStatement( 
  sql); 
 
 
 
       } 
 
 
 
        
  /** 
 
 
  
       
   * Factory method that creates and initializes a <code>Connection</code> 
 
 
  
       
   * object. <code>QueryRunner</code> methods always call this method to 
 
 
  
       
   * retrieve connections from its DataSource. Subclasses can override this 
 
 
  
       
   * method to provide special <code>Connection</code> configuration if 
 
 
  
       
   * needed. This implementation simply calls <code>ds.getConnection()</code>. 
 
 
  
       
   *  
 
 
  
       
   * 工厂方法,创建和实例化一个Connection对象。QueryRunner中的方法总会调用此方法从数据源中获得数据库 
 
 
  
       
   * 连接。需要的话,子类可以覆写此方法来提供特殊的连接配置。这里只是简单地调用了数据源的getConnection() 
 
 
  
  
  
       
   *             if a database access error occurs 
 
 
  
  
       
   */ 
 
 
 
        
  protected  
  Connection  
  prepareConnection()  
  throws  
  SQLException { 
 
 
  
           
  if ( 
  this. 
  getDataSource()  
  ==  
  null) { 
 
 
  
       
           
  throw  
  new  
  SQLException( 
 
 
  
       
       
       
           
  "QueryRunner requires a DataSource to be " 
 
 
  
       
       
       
           
  +  
  "invoked in this way, or a Connection should be passed in"); 
 
 
  
          } 
 
 
  
           
  return  
  this. 
  getDataSource(). 
  getConnection(); 
 
 
 
       } 
 
 
 
        
  /** 
 
 
  
       
   * Fill the <code>PreparedStatement</code> replacement parameters with the 
 
 
  
       
   * given objects. 
 
 
  
       
   * 使用给定的对象,填充PreparedStatement中的参数 
 
 
  
       
   *  
  @param 
   stmt 
 
 
  
       
   *            PreparedStatement to fill 
 
 
  
       
   *  
  @param 
   params 
 
 
  
       
   *            Query replacement parameters; <code>null</code> is a valid 
 
 
  
       
   *            value to pass in. 
 
 
  
  
       
   *             if a database access error occurs 
 
 
  
       
   */ 
 
 
 
        
  public  
  void  
  fillStatement( 
  PreparedStatement  
  stmt,  
  Object...  
  params) 
 
 
 
        
  throws  
  SQLException { 
 
 
  
           
  // check the parameter count, if we can 
 
 
  
           
  ParameterMetaData  
  pmd  
  =  
  null; 
 
 
  
           
  if ( 
  ! 
  pmdKnownBroken) {  
  //pmdKnownBroken初始化值是false 
 
 
  
       
           
  pmd  
  =  
  stmt. 
  getParameterMetaData(); 
  //获得元数据 
 
 
  
       
           
  int  
  stmtCount  
  =  
  pmd. 
  getParameterCount(); 
  //获得占位符的个数 
 
 
  
       
           
  int  
  paramsCount  
  =  
  params  
  ==  
  null ?  
  0 :  
  params. 
  length; 
  //给定参数的个数 
 
 
  
       
           
  if ( 
  stmtCount  
  !=  
  paramsCount) { 
  //如果占位符和给定参数的个数不一致,报错 
 
 
  
       
       
           
  throw  
  new  
  SQLException( 
  "Wrong number of parameters: expected " 
 
 
  
       
       
       
       
           
  +  
  stmtCount  
  +  
  ", was given "  
  +  
  paramsCount); 
 
 
  
       
          } 
 
 
  
          } 
 
 
  
           
  // nothing to do here 
 
 
  
           
  if ( 
  params  
  ==  
  null) {  
  //给定参数为null,什么也不做 
 
 
  
       
           
  return; 
 
 
  
          } 
 
 
  
           
  // TODO else有些不明白 
 
 
  
           
  for ( 
  int  
  i  
  =  
  0;  
  i  
  <  
  params. 
  length;  
  i 
  ++) { 
 
 
  
       
           
  if ( 
  params[ 
  i]  
  !=  
  null) { 
 
 
  
       
       
           
  stmt. 
  setObject( 
  i  
  +  
  1,  
  params[ 
  i]); 
 
 
  
       
          }  
  else { 
 
 
  
       
       
           
  // VARCHAR works with many drivers regardless 
 
 
  
       
       
           
  // of the actual column type. Oddly, NULL and 
 
 
  
       
       
           
  // OTHER don't work with Oracle's drivers. 
 
 
  
       
       
           
  int  
  sqlType  
  =  
  Types. 
  VARCHAR; 
 
 
  
       
       
           
  if ( 
  ! 
  pmdKnownBroken) { 
 
 
  
       
       
       
           
  try { 
 
 
  
       
       
       
       
           
  /* 
 
 
  
       
       
       
       
       
       
   * It's not possible for pmdKnownBroken to change from 
 
 
  
       
       
       
       
       
       
   * true to false, (once true, always true) so pmd cannot 
 
 
  
       
       
       
       
       
       
   * be null here. 
 
 
  
       
       
       
       
       
       
   */ 
 
 
  
       
       
       
       
           
  sqlType  
  =  
  pmd. 
  getParameterType( 
  i  
  +  
  1); 
 
 
  
       
       
       
          }  
  catch ( 
  SQLException  
  e) { 
 
 
  
       
       
       
       
           
  pmdKnownBroken  
  =  
  true; 
 
 
  
       
       
       
          } 
 
 
  
       
       
          } 
 
 
  
       
       
           
  stmt. 
  setNull( 
  i  
  +  
  1,  
  sqlType); 
 
 
  
       
          } 
 
 
  
          } 
 
 
 
       } 
 
 
 
        
  /** 
 
 
  
       
   * Fill the <code>PreparedStatement</code> replacement parameters with the 
 
 
  
       
   * given object's bean property values. 
 
 
  
       
   * 
 
 
  
       
   *  
  @param 
   stmt 
 
 
  
       
   *            PreparedStatement to fill 
 
 
  
       
   *  
  @param 
   bean 
 
 
  
       
   *            a JavaBean object 
 
 
  
       
   *  
  @param 
   properties 
 
 
  
       
   *            an ordered array of properties; this gives the order to insert 
 
 
  
       
   *            values in the statement 
 
 
  
  
       
   *             if a database access error occurs 
 
 
  
       
   */ 
 
 
 
        
  public  
  void  
  fillStatementWithBean( 
  PreparedStatement  
  stmt,  
  Object  
  bean, 
 
 
  
       
           
  PropertyDescriptor[]  
  properties)  
  throws  
  SQLException { 
 
 
  
           
  //定义一个Object属性,存放代替SQL中占位符的参数 
 
 
  
           
  Object[]  
  params  
  =  
  new  
  Object[ 
  properties. 
  length]; 
 
 
  
           
  //循环属性描述符数组,属性描述符要与SQL中占位符一一对应 
 
 
  
           
  for ( 
  int  
  i  
  =  
  0;  
  i  
  <  
  properties. 
  length;  
  i 
  ++) { 
 
 
  
       
           
  PropertyDescriptor  
  property  
  =  
  properties[ 
  i]; 
  //获得第i个属性 
 
 
  
       
           
  Object  
  value  
  =  
  null; 
 
 
  
       
           
  //获得第i个属性的getter方法 
 
 
  
       
           
  Method  
  method  
  =  
  property. 
  getReadMethod(); 
 
 
  
       
           
  //如果不存在getter方法,就报错 
 
 
  
       
           
  if ( 
  method  
  ==  
  null) { 
 
 
  
       
       
           
  throw  
  new  
  RuntimeException( 
  "No read method for bean property " 
 
 
  
       
       
       
       
           
  +  
  bean. 
  getClass()  
  +  
  " "  
  +  
  property. 
  getName()); 
 
 
  
       
          } 
 
 
  
       
           
  try { 
 
 
  
       
               
  //调用getter方法,获得此属性的值,因为是get方法,不用参数 
 
 
  
       
       
           
  value  
  =  
  method. 
  invoke( 
  bean,  
  new  
  Object[ 
  0]); 
 
 
  
       
          }  
  catch ( 
  InvocationTargetException  
  e) { 
 
 
  
       
       
           
  throw  
  new  
  RuntimeException( 
  "Couldn't invoke method: "  
  +  
  method, 
 
 
  
       
       
       
       
           
  e); 
 
 
  
       
          }  
  catch ( 
  IllegalArgumentException  
  e) { 
 
 
  
       
       
           
  throw  
  new  
  RuntimeException( 
 
 
  
       
       
       
       
           
  "Couldn't invoke method with 0 arguments: "  
  +  
  method,  
  e); 
 
 
  
       
          }  
  catch ( 
  IllegalAccessException  
  e) { 
 
 
  
       
       
           
  throw  
  new  
  RuntimeException( 
  "Couldn't invoke method: "  
  +  
  method, 
 
 
  
       
       
       
       
           
  e); 
 
 
  
       
          } 
 
 
  
       
           
  //获得了属性值后就存放到Object数组中 
 
 
  
       
           
  params[ 
  i]  
  =  
  value; 
 
 
  
          } 
 
 
  
           
  //最后,调用fillStatement来填充SQL中的占位符 
 
 
  
           
  fillStatement( 
  stmt,  
  params); 
 
 
 
       } 
 
 
 
        
  /** 
 
 
  
       
   * Fill the <code>PreparedStatement</code> replacement parameters with the 
 
 
  
       
   * given object's bean property values. 
 
 
  
       
   * 此方法跟fillStatementWithBean(PreparedStatement stmt, Object bean, 
 
 
  
       
   *       PropertyDescriptor[] properties)类似,一个是用了属性描述符,这里是直接 
 
 
  
       
   * 使用了属性名。 
 
 
  
       
   * 在方法内部将属性变成属性描述符,然后即可。 
 
 
  
       
   * 
 
 
  
       
   *  
  @param 
   stmt 
 
 
  
       
   *            PreparedStatement to fill 
 
 
  
       
   *  
  @param 
   bean 
 
 
  
       
   *            A JavaBean object 
 
 
  
       
   *  
  @param 
   propertyNames 
 
 
  
       
   *            An ordered array of property names (these should match the 
 
 
  
       
   *            getters/setters); this gives the order to insert values in the 
 
 
  
       
   *            statement 
 
 
  
  
       
   *             If a database access error occurs 
 
 
  
       
   */ 
 
 
 
        
  public  
  void  
  fillStatementWithBean( 
  PreparedStatement  
  stmt,  
  Object  
  bean, 
 
 
  
       
           
  String...  
  propertyNames)  
  throws  
  SQLException { 
 
 
  
           
  PropertyDescriptor[]  
  descriptors; 
 
 
  
           
  try { 
 
 
  
       
           
  descriptors  
  =  
  Introspector. 
  getBeanInfo( 
  bean. 
  getClass()) 
 
 
  
       
          . 
  getPropertyDescriptors(); 
 
 
  
          }  
  catch ( 
  IntrospectionException  
  e) { 
 
 
  
       
           
  throw  
  new  
  RuntimeException( 
  "Couldn't introspect bean " 
 
 
  
       
       
       
           
  +  
  bean. 
  getClass(). 
  toString(),  
  e); 
 
 
  
          } 
 
 
  
           
  PropertyDescriptor[]  
  sorted  
  =  
  new  
  PropertyDescriptor[ 
  propertyNames. 
  length]; 
 
 
  
           
  for ( 
  int  
  i  
  =  
  0;  
  i  
  <  
  propertyNames. 
  length;  
  i 
  ++) { 
 
 
  
       
           
  String  
  propertyName  
  =  
  propertyNames[ 
  i]; 
 
 
  
       
           
  if ( 
  propertyName  
  ==  
  null) { 
 
 
  
       
       
           
  throw  
  new  
  NullPointerException( 
  "propertyName can't be null: " 
 
 
  
       
       
       
       
           
  +  
  i); 
 
 
  
       
          } 
 
 
  
       
           
  boolean  
  found  
  =  
  false; 
 
 
  
       
           
  for ( 
  int  
  j  
  =  
  0;  
  j  
  <  
  descriptors. 
  length;  
  j 
  ++) { 
 
 
  
       
       
           
  PropertyDescriptor  
  descriptor  
  =  
  descriptors[ 
  j]; 
 
 
  
       
       
           
  if ( 
  propertyName. 
  equals( 
  descriptor. 
  getName())) { 
 
 
  
       
       
       
           
  sorted[ 
  i]  
  =  
  descriptor; 
 
 
  
       
       
       
           
  found  
  =  
  true; 
 
 
  
       
       
       
           
  break; 
 
 
  
       
       
          } 
 
 
  
       
          } 
 
 
  
       
           
  if ( 
  ! 
  found) { 
 
 
  
       
       
           
  throw  
  new  
  RuntimeException( 
  "Couldn't find bean property: " 
 
 
  
       
       
       
       
           
  +  
  bean. 
  getClass()  
  +  
  " "  
  +  
  propertyName); 
 
 
  
       
          } 
 
 
  
          } 
 
 
  
           
  fillStatementWithBean( 
  stmt,  
  bean,  
  sorted); 
 
 
 
       } 
 
 
 
        
  /** 
 
 
  
       
   * Throws a new exception with a more informative error message. 
 
 
  
       
   * 
 
 
  
       
   *  
  @param 
   cause 
 
 
  
       
   *            The original exception that will be chained to the new 
 
 
  
       
   *            exception when it's rethrown. 
 
 
  
       
   * 
 
 
  
       
   *  
  @param 
   sql 
 
 
  
       
   *            The query that was executing when the exception happened. 
 
 
  
       
   * 
 
 
  
       
   *  
  @param 
   params 
 
 
  
       
   *            The query replacement parameters; <code>null</code> is a valid 
 
 
  
       
   *            value to pass in. 
 
 
  
       
   * 
 
 
  
  
       
   *             if a database access error occurs 
 
 
  
       
   */ 
 
 
 
        
  protected  
  void  
  rethrow( 
  SQLException  
  cause,  
  String  
  sql,  
  Object...  
  params) 
 
 
 
        
  throws  
  SQLException { 
 
 
  
           
  String  
  causeMessage  
  =  
  cause. 
  getMessage(); 
 
 
  
           
  if ( 
  causeMessage  
  ==  
  null) { 
 
 
  
       
           
  causeMessage  
  =  
  ""; 
 
 
  
          } 
 
 
  
           
  StringBuffer  
  msg  
  =  
  new  
  StringBuffer( 
  causeMessage); 
 
 
  
           
  msg. 
  append( 
  " Query: "); 
 
 
  
           
  msg. 
  append( 
  sql); 
 
 
  
           
  msg. 
  append( 
  " Parameters: "); 
 
 
  
           
  if ( 
  params  
  ==  
  null) { 
 
 
  
       
           
  msg. 
  append( 
  "[]"); 
 
 
  
          }  
  else { 
 
 
  
       
           
  msg. 
  append( 
  Arrays. 
  deepToString( 
  params)); 
 
 
  
          } 
 
 
  
           
  SQLException  
  e  
  =  
  new  
  SQLException( 
  msg. 
  toString(),  
  cause. 
  getSQLState(), 
 
 
  
       
       
           
  cause. 
  getErrorCode()); 
 
 
  
           
  e. 
  setNextException( 
  cause); 
 
 
  
           
  throw  
  e; 
 
 
 
       } 
 
 
 
        
  /** 
 
 
  
       
   * Wrap the <code>ResultSet</code> in a decorator before processing it. This 
 
 
  
       
   * implementation returns the <code>ResultSet</code> it is given without any 
 
 
  
       
   * decoration. 
 
 
  
       
   *  
 
 
  
       
   * <p> 
 
 
  
       
   * Often, the implementation of this method can be done in an anonymous 
 
 
  
       
   * inner class like this: 
 
 
  
       
   * </p> 
 
 
  
       
   * 
 
 
  
       
   * <pre> 
 
 
  
       
   * QueryRunner run = new QueryRunner() { 
 
 
  
       
   *     protected ResultSet wrap(ResultSet rs) { 
 
 
  
       
   *         return StringTrimmedResultSet.wrap(rs); 
 
 
  
       
   *     } 
 
 
  
       
   * }; 
 
 
  
       
   * </pre> 
 
 
  
       
   * 
 
 
  
       
   *  
  @param 
   rs 
 
 
  
       
   *            The <code>ResultSet</code> to decorate; never 
 
 
  
       
   *            <code>null</code>. 
 
 
  
  
       
   */ 
 
 
 
        
  protected  
  ResultSet  
  wrap( 
  ResultSet  
  rs) { 
 
 
 
            
  //包装结果集,这里没有进行任何的包装 
 
 
  
           
  return  
  rs; 
 
 
 
       } 
 
 
 
        
  /** 
 
 
  
       
   * Close a <code>Connection</code>. This implementation avoids closing if 
 
 
  
       
   * null and does <strong>not</strong> suppress any exceptions. Subclasses 
 
 
  
       
   * can override to provide special handling like logging. 
 
 
  
       
   * 关闭Connection 
 
 
  
       
   *  
  @param 
   conn 
 
 
  
       
   *            Connection to close 
 
 
  
  
       
   *             if a database access error occurs 
 
 
  
  
       
   */ 
 
 
 
        
  protected  
  void  
  close( 
  Connection  
  conn)  
  throws  
  SQLException { 
 
 
  
           
  DbUtils. 
  close( 
  conn); 
 
 
 
       } 
 
 
 
        
  /** 
 
 
  
       
   * Close a <code>Statement</code>. This implementation avoids closing if 
 
 
  
       
   * null and does <strong>not</strong> suppress any exceptions. Subclasses 
 
 
  
       
   * can override to provide special handling like logging. 
 
 
  
       
   * 关闭Statement 
 
 
  
       
   *  
  @param 
   stmt 
 
 
  
       
   *            Statement to close 
 
 
  
  
       
   *             if a database access error occurs 
 
 
  
  
       
   */ 
 
 
 
        
  protected  
  void  
  close( 
  Statement  
  stmt)  
  throws  
  SQLException { 
 
 
  
           
  DbUtils. 
  close( 
  stmt); 
 
 
 
       } 
 
 
 
        
  /** 
 
 
  
       
   * Close a <code>ResultSet</code>. This implementation avoids closing if 
 
 
  
       
   * null and does <strong>not</strong> suppress any exceptions. Subclasses 
 
 
  
       
   * can override to provide special handling like logging. 
 
 
  
       
   * 关闭ResultSet 
 
 
  
       
   *  
  @param 
   rs 
 
 
  
       
   *            ResultSet to close 
 
 
  
  
       
   *             if a database access error occurs 
 
 
  
  
       
   */ 
 
 
 
        
  protected  
  void  
  close( 
  ResultSet  
  rs)  
  throws  
  SQLException { 
 
 
  
           
  DbUtils. 
  close( 
  rs); 
 
 
 
       } 
 
 
 
   } 
 
 
 从这里,我们可以只是,相对于JDBC编程,AbstractQueryRunner已经帮我们封装了一下几步:
1、获得数据库连接
2、获得PreparedStatement
3、为PreparedStatement中的参数设置值
这里缺少了最重要的一步,dbutils对于ResultSet怎样处理?这就要下次再说了。
PS:在这里讲一下 DbUtils中的close方法。在 AbstractQueryRunner的3个close方法中(关闭RS,关闭PS,关闭Connection)中就是调用了DbUtils中相对应的close方法。
        
  /** 
 
 
  
       
   * Close a <code>Connection</code>, avoid closing if null. 
 
 
  
       
   * 关闭Connection。学习数据源时,我们知道从DataSource中获得的Connection的close方法 
 
 
  
       
   * 是将Connection放回Connection pool中,并不是真正地关闭它。 
 
 
  
       
   *  
  @param 
   conn Connection to close. 
 
 
  
  
       
   */ 
 
 
 
        
  public  
  static  
  void  
  close( 
  Connection  
  conn)  
  throws  
  SQLException { 
 
 
  
           
  //如果不是null,就关闭 
 
 
  
           
  if ( 
  conn  
  !=  
  null) { 
 
 
  
       
           
  conn. 
  close(); 
 
 
  
          } 
 
 
 
       } 
 
 
 
        
  /** 
 
 
  
       
   * Close a <code>ResultSet</code>, avoid closing if null. 
 
 
  
       
   * 关闭RS。避免了空指针 
 
 
  
       
   *  
  @param 
   rs ResultSet to close. 
 
 
  
  
       
   */ 
 
 
 
        
  public  
  static  
  void  
  close( 
  ResultSet  
  rs)  
  throws  
  SQLException { 
 
 
  
           
  if ( 
  rs  
  !=  
  null) { 
 
 
  
       
           
  rs. 
  close(); 
 
 
  
          } 
 
 
 
       } 
 
 
 
        
  /** 
 
 
  
       
   * Close a <code>Statement</code>, avoid closing if null. 
 
 
  
       
   * 关闭Statement。避免了空指针 
 
 
  
       
   *  
  @param 
   stmt Statement to close. 
 
 
  
  
       
   */ 
 
 
 
        
  public  
  static  
  void  
  close( 
  Statement  
  stmt)  
  throws  
  SQLException { 
 
 
  
           
  if ( 
  stmt  
  !=  
  null) { 
 
 
  
       
           
  stmt. 
  close(); 
 
 
  
          } 
 
 
 
       } 
 
 
来源:oschina
链接:https://my.oschina.net/u/198574/blog/160902