论坛首页 入门技术论坛

对 DBUtils 包中 BeanProcessor 的优化

浏览 3313 次
该帖已经被评为新手帖
作者 正文
   发表时间:2010-11-03   最后修改:2010-11-03
公司正在做的一个项目中使用了 BeanProcessor 来将 ResultSet 转换为 Bean , 数据库中有个表有 300 多个字段(这里暂且不论数据库设计上的问题), 这时发现将结果集实例化的过程比较耗时, 分析了一下 BeanProcessor 的源码,发现问题出在 mapColumnsToProperties 这个方法:
	public Object toBean(ResultSet rs, Class type) throws SQLException {
		...
		int[] columnToProperty = mapColumnsToProperties(rsmd, props);
		...
	}

	public List toBeanList(ResultSet rs, Class type) throws SQLException {
		...
		int[] columnToProperty = mapColumnsToProperties(rsmd, props);
		...
	}

	private Object createBean(ResultSet rs, Class type,
	    PropertyDescriptor[] props, int[] columnToProperty) throws SQLException {
		...
		for (int i = 1; i < columnToProperty.length; ++i) {
			...
		}

		...
	}

	protected int[] mapColumnsToProperties(ResultSetMetaData rsmd,
	    PropertyDescriptor[] props) throws SQLException {
		int cols = rsmd.getColumnCount();
		int[] columnToProperty = new int[cols + 1];
		Arrays.fill(columnToProperty, -1);

		for (int col = 1; col <= cols; ++col) {
			String columnName = getPropertyName(rsmd.getColumnName(col));
			for (int i = 0; i < props.length; ++i) {
				if (columnName.equalsIgnoreCase(props[i].getName())) {
					columnToProperty[col] = i;
					break;
				}
			}
		}

		return columnToProperty;
	}

这样在全字段查询时,外层循环有300多次,内存循环又有300多次,耗时的部分就在这个嵌套循环里面(当然,一般情况下字段数不多时,这里的差别可以忽略不计)。



于是着手改了一下:
	...
	private Map properties = new HashMap();

	public Object toBean(ResultSet rs, Class type) throws SQLException {
		PropertyDescriptor[] props = propertyDescriptors(type);

		for (int i = 0; i < props.length; i++) {//将实体类所有属性放到Map中
			properties.put(props[i].getName(), props[i]);
		}

		return createBean(rs, type);
	}

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

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

		PropertyDescriptor[] props = propertyDescriptors(type);
		for (int i = 0; i < props.length; i++) {//将实体类所有属性放到Map中
			properties.put(props[i].getName(), props[i]);
		}
		do {
			results.add(createBean(rs, type));
		} while (rs.next());

		return results;
	}

	private Object createBean(ResultSet rs, Class type) throws SQLException {
		Object bean = newInstance(type);
		ResultSetMetaData rsmd = rs.getMetaData();
		int cols = rsmd.getColumnCount();
		for (int col = 1; col <= cols; col++) {
			String columnName = getPropertyName(rsmd.getColumnName(col));
			if (properties.containsKey(columnName)) {//实体类存在该属性
				PropertyDescriptor prop = (PropertyDescriptor) properties.get(columnName);
				Class propType = prop.getPropertyType();
				Object value = processColumn(rs, col, propType);
				if ((propType != null) && (value == null) && (propType.isPrimitive())) {
					value = primitiveDefaults.get(propType);
				}

				callSetter(bean, prop, value);
			}
		}

		return bean;
	}
	...
	...

姑且算字段数为 300 , 用 toBean 方法转换一个实体
这样改动后的效果就是将原来的约 300 * 300 + 300 次的循环(忽略内层循环里的 break) 变为 300 + 300 次循环。


BTW:如果发现问题,欢迎指正。

   发表时间:2010-12-31  
很好的思路,不过请教一下:
private final Map<String, PropertyDescriptor> properties = new Hashtable<String, PropertyDescriptor>();

我觉得将HashMap改成Hashtable是不是好点?
0 请登录后投票
   发表时间:2010-12-31  
若你有较好的改进思路和实现代码,建议你给dbutils发送邮件说明你的改进意见和代码。让大家都能享受到你的劳动成果。
0 请登录后投票
论坛首页 入门技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics