`

Commons DbUtils 源码阅读四

阅读更多

  在读BasicRowProcessor 类时,它有两个方法(toBean和toBeanList)都将最终的处理工作交给了BeanProcessor,所以,今天来拜读一下此类, 在读此类的时候,决定换个方式,就一个方法慢慢的展开分析,这样或许也会更有趣味和吸引力吧:

 

	public <T> T toBean(ResultSet rs, Class<T> type) throws SQLException {

		PropertyDescriptor[] props = this.propertyDescriptors(type);// 1)获取指定类的属性描述对象集合

		ResultSetMetaData rsmd = rs.getMetaData();
		int[] columnToProperty = this.mapColumnsToProperties(rsmd, props);//2)列名转换为bean属性

		return this.createBean(rs, type, props, columnToProperty);//3)
	}

 

  这个方法呢,是将ResultSet的指定行创建一个指定类型的Bean实例返回:

  1) 这个是利用内省机制,获取指定类的属性描述数组,来看看这个propertyDescriptors方法

 

	private PropertyDescriptor[] propertyDescriptors(Class<?> c)
			throws SQLException {
		// Introspector caches BeanInfo classes for better performance
		BeanInfo beanInfo = null;
		try {
			beanInfo = Introspector.getBeanInfo(c);

		} catch (IntrospectionException e) {
			throw new SQLException("Bean introspection failed: "
					+ e.getMessage());
		}

		return beanInfo.getPropertyDescriptors();
	}

   通过Introspector的静态方法getBeanInfo,获取指定类型的BeanInfo实例,再调用getPropertyDescriptors()方法返回该类的所有PropertyDescriptor数组,非常的简洁明了,这个就是传说中的内省了

  2) 这个方法的功能呢,是将column数组与类的properties匹配,两个都是数组,然后返回还是个数组,居然还map名,所以,看看里面是如何实现的:

 

	protected int[] mapColumnsToProperties(ResultSetMetaData rsmd,
			PropertyDescriptor[] props) throws SQLException {

		int cols = rsmd.getColumnCount();
		int columnToProperty[] = new int[cols + 1];
		Arrays.fill(columnToProperty, PROPERTY_NOT_FOUND);

		for (int col = 1; col <= cols; col++) {
			String columnName = rsmd.getColumnLabel(col);//获取列名
			if (null == columnName || 0 == columnName.length()) {
				columnName = rsmd.getColumnName(col);
			}
			for (int i = 0; i < props.length; i++) {

				if (columnName.equalsIgnoreCase(props[i].getName())) {//与属性名进行匹配					columnToProperty[col] = i;
					break;
				}
			}
		}
		// comlumnToProperty 里面返回的是column下标对应的PropertyDescriptor属性的下标值

		return columnToProperty;
	}

   这个方法的所做的工作实际上是这样的,将ResultSet中的列名与Bean的属性进行匹配,声明的数组的长度是以ResultSet中的列数量来确定的,所以下标从1开始,然后与Bean的PropertyDescriptor数组进行属性名匹配,如果有找到,则在对应的列名下标数组里存入bean属性的位置。这样一来,我们就可以清晰的知道,ResultSet列名对应的Bean属性了。

  OK,也许你现在看这段话有些稀里糊涂,你只要记住,这个返回的数组是按照ResultSet的列标匹配bean属性数组对应的位置的。

  3)看关键方法

 

    private <T> T createBean(ResultSet rs, Class<T> type,
            PropertyDescriptor[] props, int[] columnToProperty)
            throws SQLException {

        T bean = this.newInstance(type);//创建该类实例
        //循环列名与bean属性匹配情况数组
        for (int i = 1; i < columnToProperty.length; i++) {

            if (columnToProperty[i] == PROPERTY_NOT_FOUND) {//该下标没有匹配的属性,则不做处理
                continue;
            }

            PropertyDescriptor prop = props[columnToProperty[i]];//获取对应属性的描述对象
            Class<?> propType = prop.getPropertyType();//获取类型

            Object value = this.processColumn(rs, i, propType);//获取rs对应的值

            if (propType != null && value == null && propType.isPrimitive()) {
                value = primitiveDefaults.get(propType);//为空,获取默认值
            }

            this.callSetter(bean, prop, value);//调用属性的setter方法
        }

        return bean;
    }

   这个方法呢,首先来生成一个指定类型的实例,然后循环之前处理ResultSet列名与Bean属性名匹配情况的数组,获取Bean属性特定的PropertyDescriptor实例,通过this.processColumn(rs, i, propType)这个方法获取数据库中对应的值,再调用callSetter(...)方法来为新建Bean实例赋值上值,来看看它是怎么实现的:

 

 Method setter = prop.getWriteMethod();//通过PropertyDescriptor获取对应属性的Setter方法

 

 然后匹配数据库类型与Bean方法的类型,如果不匹配,则抛出异常,否则通过反射来为Bean对象填入对应的值,来看具体实现:

 

Class<?>[] params = setter.getParameterTypes();//参数类型列表
 ............................................................................

// Don't call setter if the value object isn't the right type 
  if (this.isCompatibleType(value, params[0])) {
                setter.invoke(target, new Object[] { value });
 } else {
              throw new SQLException(
                  "Cannot set " + prop.getName() + ": incompatible types.");
 }

 我们深刻的分析了一下toBean方法,toBeanList方法呢,实际上就是循环ResultSet,获取每一行,然后交由toBean()方法处理,贴出具体的代码:

 

    public <T> List<T> toBeanList(ResultSet rs, Class<T> type) throws SQLException {
        List<T> results = new ArrayList<T>();

        if (!rs.next()) {
            return results;
        }
              
        PropertyDescriptor[] props = this.propertyDescriptors(type);
        ResultSetMetaData rsmd = rs.getMetaData();
        int[] columnToProperty = this.mapColumnsToProperties(rsmd, props);
       
        do {
            results.add(this.createBean(rs, type, props, columnToProperty));
        } while (rs.next());

        return results;
    }

     这个方法,我没有搞明白为什么不直接循环调用toBean()方法,直接调用toBean()方法不好嘛?!(或许是我资力尚浅,没有明白作者的意图)

    这里也贴出个人认为可以完善的这个方法实现吧

 

//        PropertyDescriptor[] props = this.propertyDescriptors(type);
//        ResultSetMetaData rsmd = rs.getMetaData();
//        int[] columnToProperty = this.mapColumnsToProperties(rsmd, props);

        do {
//            results.add(this.createBean(rs, type, props, columnToProperty));
        	results.add(this.toBean(rs, type));//修改部分
        } while (rs.next());

  如果有朋友认为我这样写不对,还请不吝教导。

 

 

 

分享到:
评论
4 楼 lgh1992314 2017-08-25  
1.7
public <T> List<T> toBeanList(ResultSet rs, Class<T> type) throws SQLException {
        List<T> results = new ArrayList<T>();

        if (!rs.next()) {
            return results;
        }

        PropertyDescriptor[] props = this.propertyDescriptors(type);
        ResultSetMetaData rsmd = rs.getMetaData();
        int[] columnToProperty = this.mapColumnsToProperties(rsmd, props);

        do {
            results.add(this.createBean(rs, type, props, columnToProperty));
        } while (rs.next());

        return results;
    }
3 楼 lgh1992314 2017-08-25  
it was too slow to call the method mapColumnsToProperties for each row returned by the result set.
That’s also why there is a toBeanList method in the RowProcessor interface.
2 楼 yenshen 2014-04-15  
toBeanList不直接循环调用toBean()方法
是因为会多次调用原本只需调用一次的 propertyDescriptors(type)方法 和 mapColumnsToProperties(rsmd, props)方法
1 楼 xfei6868 2011-11-02  
最后一个好像他的做法的好处就是不用每次

PropertyDescriptor[] props = this.propertyDescriptors(type); 
    ResultSetMetaData rsmd = rs.getMetaData(); 
    int[] columnToProperty = this.mapColumnsToProperties(rsmd, props)

做这些事情, 有点浪费

相关推荐

    commons-dbutils-1.7-API文档-中文版.zip

    赠送源代码:commons-dbutils-1.7-sources.jar; 赠送Maven依赖信息文件:commons-dbutils-1.7.pom; 包含翻译后的API文档:commons-dbutils-1.7-javadoc-API文档-中文(简体)版.zip; Maven坐标:commons-dbutils:...

    Commons-dbutils1.7 jar包.rar

    commons-dbutils包是Apache开源组织提供的用于操作数据库的工具包。简单来讲,这个工具包就是用来更加方便我们操作数据库的,最近工作中使用了一下,感觉确实方便很多,基本告别自己封装JDBC代码对数据库进行增删改...

    Commons DbUtils源码阅读之实例及测试应用

    NULL 博文链接:https://cuics-100.iteye.com/blog/920565

    commons-dbutils-1.7-API文档-中英对照版.zip

    赠送源代码:commons-dbutils-1.7-sources.jar; 赠送Maven依赖信息文件:commons-dbutils-1.7.pom; 包含翻译后的API文档:commons-dbutils-1.7-javadoc-API文档-中文(简体)-英语-对照版.zip; Maven坐标:commons-...

    commons-dbutils-1.6的jar包、源码、文档说明.zip

    commons-dbutils-1.6的jar包、源码、文档说明.zip

    commons-dbutils-1.4 bin+src

    commons-dbutils-1.4 jar包和源码文件,查看源码非常方便,欢迎下载

    apache-commons下源码大放送

    apache-commons下全部官方源码和官方API文档,其中有: commons-beanutils-1.8.0 commons-codec commons-collections commons-dbcp commons-dbutils commons-fileupload commons-io commons-lang commons-lang3 ...

    commons-dbutils-1.7-src.zip

    dao轻量级框架dbutils的源码

    commons-dbutils组件包与源码

    commons-dbutils组件包与源码,人个收集,提供给大家共同学习,共同进步。

    Dbutils项目实例

    DBUtils封装了对JDBC的操作 简化了JDBC操作 可以少写代码 org apache commons dbutils DbUtils 关闭链接等操作 QueryRunner 进行查询的操作 org apache commons dbutils handlers ArrayHandler :将ResultSet中第一...

    apache commons jar(commons所有的jar包,从官网下载提供.zip

    apache commons jar(commons所有的jar包,从官网下载提供给大家) 因为涉及jar太多,包括有src源代码,只需要3分,希望大家理解,我也是从官网花了很长时间才一个一个下完,需要的请自取。全部是zip文件,每个对应的...

    commons-dbutils使用简单范例--简化jdbc编程

    NULL 博文链接:https://gnnan.iteye.com/blog/1170042

    commons-dbutils-1.7-bin.zip

    dao层的一个轻量级框架,使用非常方便,是apache的一个开源项目,源码我也上传了

    org.apache.commons 的 jar 包 源码

    org.apache.commons 的 jar 包 源码 org.apache.commons 的 jar 包 源码 org.apache.commons 的 jar 包 源码

    DbUtils扩展源码

    ApacheCommos的DbUtils是一个简单好用的轻量级的数据库操作工具,该项目的主页是:http://commons.apache.org/dbutils/,关于它的信息可以从那里获取. dbutils可以把查询出来的结果集映射成Bean的List,这是个很有用的...

    commons-dbutils-1.7.jar中文-英文对照文档.zip

    源代码下载地址:【***-sources.jar下载地址(官方地址+国内镜像地址).txt】 # 本文件关键字: 中文-英文对照文档,中英对照文档,java,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,中文API文档,手册,...

    最新版commons-dbutils-1.6带源码

    官网下载的最新的2017年commons jar包资源,

    apache-commons源码及jar文件

    DbUtils 是一个 JDBC helper 类库,完成数据库任务的简单的资源清除代码. Digester Commons-Digester 是一个 XML-Java对象的映射工具,用于解析 XML配置文件. Discovery Commons-Discovery 提供工具来定位资源 ...

    apache commons jar(commons所有的jar包,从官网下载提供给大家)

    apache commons jar(commons所有的jar包,从官网下载提供给大家) 因为涉及jar太多,包括有src源代码,只需要3分,希望大家理解,我也是从官网花了很长时间才一个一个下完,需要的请自取。全部是zip文件,每个对应的...

    Dbutils学习源码总结

    apache下面有很多值得学习的开源项目,尤其是commons系列,在此,特封装了其组织下的dbutils根据,方便了喜欢使用sql开发的java朋友,里面有各种实用的封装类和对数据库操作的接口,欢迎下载!

Global site tag (gtag.js) - Google Analytics