ApacheCommos的DbUtils是一个简单好用的轻量级的数据库操作工具,该项目的主页是:http://commons.apache.org/dbutils/,关于它的信息可以从那里获取.
请看代码:
QueryRunner run = new QueryRunner(dataSource);
// Use the BeanListHandler implementation to convert all
// ResultSet rows into a List of Person JavaBeans.
ResultSetHandler<List<Person>> h = new BeanListHandler(Person.class);
// Execute the SQL statement and return the results in a List of
// Person objects generated by the BeanListHandler.
List<Person> persons = run.query("SELECT * FROM Person", h);
从以上代码可看出dbutils可以把查询出来的结果集映射成Bean的List,这是个很有用的功能,不过有一个很大限制,规定数据库字段名必须跟Bean的属性名一致,例如字段名为"my_name",那么属性名也必须为"my_name".
这个限制的影响还是比较大的,这样好像BeanListHandler就没有什么作用了?而我希望的是该工具可以定制各种各样的结果集与Bean的映射规则.比如,可以使用"驼峰规则"来匹配,字段"MY_NAME"对应的属性为"myName",或者是直接指定一个二维数组定义字段与属性之间的对应关系.
说到这里,我们的扩展目标也出来.现在,看一下dbutils的源代码是否有这方面的扩展点.先看一下BeanListHandler的相关代码.
...
public class BeanListHandler<T> implements ResultSetHandler<List<T>> {
/**
* The Class of beans produced by this handler.
*/
private final Class<T> type;
/**
* The RowProcessor implementation to use when converting rows
* into beans.
*/
private final RowProcessor convert;
public BeanListHandler(Class<T> type) {
this(type, ArrayHandler.ROW_PROCESSOR);
}
public BeanListHandler(Class<T> type, RowProcessor convert) {
this.type = type;
this.convert = convert;
}
public List<T> handle(ResultSet rs) throws SQLException {
return this.convert.toBeanList(rs, type);
}
}
根据上面的代码片断可以看出,BeanListHandler的功能是由convert(RowProcessor)提供的,而convert的默认实现为ArrayHandler.ROW_PROCESSOR.再看一下ArrayHandler.ROW_PROCESSOR的相关代码.
public class ArrayHandler implements ResultSetHandler<Object[]> {
...
static final RowProcessor ROW_PROCESSOR = new BasicRowProcessor();
...
}
很明显BeanListHandler是依赖BasicRowProcessor来完成相应的功能的.不过,这不是终点,继续看一下,会发现,真实完成字段与属性映射功能的是类BeanProcessor,再看一下BeanProcessor的源码.
...
public class BeanProcessor {
...
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;
}
...
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;
}
}
}
return columnToProperty;
}
...
}
阅读以上代码可知,方法toBeanList提供将结果集映射成包括Bean的List的功能,方法内部使用数组columnToProperty来存放各字段对应属性的索引位置,而此数组是由方法mapColumnsToProperties来提供的,而且此方法是通过columnName.equalsIgnoreCase(props[i].getName())来确定指定字段对应的属性的,就是这里造成了上面提到的限制.那么很明显这里就是要找的扩展点了.只要重写此方法就可以实现了,比如文章开头提到的各种需求.不过我觉得还有更好的扩展方法,例如可以把匹配字段名与属性名这个逻辑抽象出来作为一种策略,并且提供常用的策略以供选择,而且有新的需求同样可以通过提供新的策略来实现.这样做还有另一个好处,就是把扩展时的关注点范围缩小,集中到"匹配"这一点上来,而不去关心其它问题.这样的好处可想而知,可以很容易的写出实现与明确的单元测试.
好了,以下为我的扩展的实现,首先是StrategyBeanProcessor:
package com.yang.commons.dbutils;
import java.beans.PropertyDescriptor;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.Arrays;
import org.apache.commons.dbutils.BeanProcessor;
/**
* 策略模式的BeanProcessor
* @author 刘晓阳
* @since 2010-02-05
*/
public class StrategyBeanProcessor extends BeanProcessor {
private Matcher matcher;
public StrategyBeanProcessor(){
// 默认Matcher
matcher = new EqualsIgnoreCaseMatcher();
}
public StrategyBeanProcessor(Matcher matcher){
this.matcher = matcher;
}
public Matcher getMatcher() {
return matcher;
}
public void setMatcher(Matcher matcher) {
this.matcher = matcher;
}
/**
* 重写BeanProcessor的实现,使用策略模式
*/
protected int[] mapColumnsToProperties(ResultSetMetaData rsmd,
PropertyDescriptor[] props) throws SQLException {
if (matcher == null)
throw new IllegalStateException("Matcher must be setted!");
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 (matcher.match(columnName, props[i].getName())) {//与BeanProcessor不同的地方
columnToProperty[col] = i;
break;
}
}
}
return columnToProperty;
}
}
StrategyBeanProcessor重写了BeanProcessor的mapColumnsToProperties方法,把原先写死的字段名与属性名的匹配逻辑交由Matcher来实现.Matcher是一个接口,它是"字段名与属性名是否匹配"的抽象.继续,下面是接口Matcher:
package com.yang.commons.dbutils;
/**
* 字段名与属性名的匹配器
* @author 刘晓阳
* @since 2010-02-05
*/
public interface Matcher {
/**
* 是否匹配
* @param columnName 字段名
* @param propertyName 属性名
* @return 匹配结果
*/
boolean match(String columnName, String propertyName);
}
接口Matcher非常简单,只有一个方法match.再看一下两个常用实现,分别是MappingMatcher与HumpMatcher:
package com.yang.commons.dbutils;
import java.util.HashMap;
import java.util.Map;
/**
* 二维数组映射的匹配器
* @author 刘晓阳
* @since 2010-02-05
*/
public class MappingMatcher implements Matcher {
private Map<String, String> map = null;
public MappingMatcher(String [][] mapping){
if (mapping == null)
throw new IllegalArgumentException();
map = new HashMap<String, String>();
for (int i = 0; i < mapping.length; i++){
String columnName = mapping[i][0];
if (columnName != null)
map.put(columnName.toUpperCase(), mapping[i][1]);
}
}
/*
* (non-Javadoc)
* @see com.yang.commons.dbutils.Matcher#match(java.lang.String, java.lang.String)
*/
public boolean match(String columnName, String propertyName) {
if (columnName == null)
return false;
String pName = map.get(columnName.toUpperCase());
if (pName == null)
return false;
else {
return pName.equals(propertyName);
}
}
}
package com.yang.commons.dbutils;
/**
* 驼峰转换的匹配器
*
* @author 刘晓阳
* @since 2010-02-05
*/
public class HumpMatcher implements Matcher {
/*
* (non-Javadoc)
*
* @see com.yang.commons.dbutils.Matcher#match(java.lang.String,
* java.lang.String)
*/
public boolean match(String columnName, String propertyName) {
if (columnName == null)
return false;
columnName = columnName.toLowerCase();
String[] _ary = columnName.split("_");
StringBuilder strBuilder = new StringBuilder();
for (int i = 0; i < _ary.length; i++) {
String str = _ary[i];
if (!"".equals(str) && i > 0) {
StringBuilder _builder = new StringBuilder();
str = _builder.append(str.substring(0, 1).toUpperCase()).append(str.substring(1)).toString();
}
strBuilder.append(str);
}
return strBuilder.toString().equals(propertyName);
}
}
有了这样的扩展,以后就可以这样写代码了:
QueryRunner run = new QueryRunner(dataSource);
ResultSetHandler<List<Person>> h = new BeanListHandler(Person.class, new BasicRowProcessor(new StrategyBeanProcessor(new HumpMatcher())));
List<Person> persons = run.query("SELECT * FROM Person", h);
现在可以满足文章前面提出的需求了,并且在有新的需求出现的情况下,也可以很容易的满足.
注:附件提供了源代码
分享到:
相关推荐
DBUtils 是一个非常重要的 Python 模块,专为数据库连接设计,它在 Python 的数据库应用开发中扮演着不可或缺的角色。这个模块主要目的是提供一个稳定、健壮的接口,用于管理和操作数据库连接,使得开发者能够更方便...
ApacheCommos的DbUtils是一个简单好用的轻量级的数据库操作工具,该项目的主页是:http://commons.apache.org/dbutils/,关于它的信息可以从那里获取. dbutils可以把查询出来的结果集映射成Bean的List,这是个很有用的...
Python的DBUtils是一个非常实用的库,主要用于增强Python标准库中的`DB-API 2.0`接口,提供了线程安全性和连接池管理等功能。DBUtils是基于PEP 249设计的,它使得数据库连接的管理和维护变得更加简单,尤其在多线程...
`commons-dbutils-1.6-sources.jar`包含了源代码,这对于开发者来说是极其宝贵的资源,因为可以方便地查看和理解DBUtils内部的工作机制,进行调试或自定义扩展。 DBUtils的设计原则是简单、高效和健壮。它不是ORM...
Dbutils 是 Apache Commons DbUtils 的简称,它是一个用于简化 Java 数据库编程的开源库。Dbutils 基于 JDBC(Java Database Connectivity),提供了一套简洁、高效且易于使用的API,帮助开发者更方便地处理数据库...
- **自定义函数**: 可以扩展`dbutils` API,通过`dbutils.functions.addPyFile()` 加载自定义Python模块。 ### 5. 注意事项 - 文件操作时确保有权限访问路径。 - 变量管理需注意变量名的唯一性和命名规则。 - ...
`commons-dbutils.jar.rar` 是一个包含Apache Commons DBUtils库的不同版本的压缩文件,主要用于Java应用程序中的数据库操作。DBUtils是一个实用程序库,它简化了JDBC(Java Database Connectivity)的使用,提供了...
《Apache Commons DBUtils详解及其在Java数据库操作中的应用》 Apache Commons DBUtils是Apache软件基金会开发的一个开源项目,它提供了一套简洁、高效且实用的工具类,用于简化Java应用程序中的数据库操作。这个...
DBUtils是Apache Commons库中的一个组件,它提供了一套简单易用的数据库操作API,用于简化Java中的数据库访问。在本项目中,你将找到一个自己编写的简易DBUtils实现,虽然它不是Apache官方的DBUtils,但其设计思想和...
Apache Commons DBUtils是一个Java库,它简化了与数据库交互的任务,是Java开发中常用的数据访问工具。这个压缩包“commons-dbutils-1.3.zip”包含的是DBUtils库的1.3版本。DBUtils库是Apache Commons项目的一部分,...
Apache Commons DbUtils是Java开发中的一个实用工具库,专门针对JDBC(Java Database Connectivity)进行优化,以提供更简洁、高效的数据库操作API。这个库在Java社区中广泛使用,因为它大大减轻了开发者处理数据库...
C3P0和DBUtils是两个非常重要的库,用于简化Java应用程序中的数据库操作。以下是这两个库的详细介绍: C3P0是一个开源的JDBC连接池,它的全称是Commerical-grade Connection Pooling for JDBC。C3P0-0.9.1.2.jar是...
这为用户提供了深入理解库内部工作原理的机会,也可以根据需要进行定制或扩展。源代码可以用于学习、调试和贡献到开源项目中。 标签"dbutils"和"jdbc"揭示了DBUtils的核心功能。DBUtils主要与JDBC接口协同工作,...
DBUtils 是一套允许线程化 Python 程序可以安全和有效的访问数据库的模块。DBUtils已经作为 Webware for Python 一部分用来结合 PyGreSQL 访问 PostgreSQL 数据库,当然他也可以用在其他Python应用程序中来访问 DB-...
- 源代码可以帮助开发者扩展DbUtils,或者根据需求定制自己的数据库访问工具。 5. **应用场景**: - 快速开发小型应用,不需大型ORM框架。 - 教学示例,展示如何简化JDBC操作。 - 数据库脚本执行,如批量插入、...
赠送jar包:commons-dbutils-1.7.jar; 赠送原API文档:commons-dbutils-1.7-javadoc.jar; 赠送源代码:commons-dbutils-1.7-sources.jar; 赠送Maven依赖信息文件:commons-dbutils-1.7.pom; 包含翻译后的API文档...
C3P0是一个开放源代码的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。 1. **添加依赖**: - 添加DBUtils和C3P0的jar包到项目中。 - 如果使用Maven或者Gradle等构建工具,则可以在`pom...
Python DBUtils 是一个非常实用的库,专门设计用于管理和优化Python程序与数据库之间的连接。它遵循Python的DB-API 2规范,确保与多种数据库适配器兼容,如psycopg2(PostgreSQL)、pyodbc(ODBC)、sqlite3等。...