dbutils工具包分析及应用

原创 2017年07月18日 15:40:43

背景

项目开发过程中,需要更换数据库,DAO层抽象了一个顶层的父类,以此类着手重写一整套操作,可以将换库工作量降低到最少。那么工作量就落在了解决ORM映射问题上,原来使用的BSONObject工具包,直接完成Java对象到JSON对象的转换。现在需要利用原始的JDBC、重写一套ORM映射机制。

百度到了dbutils这个工具包,在熟悉了基本的使用方法之后,确定它能满足基本的功能。又用杯具打开它的jar包,仔细分析了下源码,发现它短小精悍,结构清晰,整理如下。

主要API类

dbutils是基于JDBC的Connection、PreparedStatement、ResultSet和ParameterMetaData等基本的类实现SQL操作结果和Java实体的映射的。主要调用接口是QueryRunner类,可以直接传递Connection对象,也可以通过数据库由QueryRunner自己获取连接对象。

它的类图结构如下:

这里写图片描述

QueryRunner提供的直接执行Sql的方法中,会在操作结束后自动调用close方法关闭相关资源,极大减少了开发人员编写JDBC操作需要的代码量。同时,它的query操作依赖于一个ResultSetHandler的实现,将查询结果集ResultSet转换成需要的对象。

ResultSetHandler实现类

dbutils提供了丰富的ResultSetHandler实现类,可以将结果集转换成单条记录、列表、Map、Java Bean、某一列的记录等,如果需要,开发人员也可以自己实现接口。

实现类图整理如下:

这里写图片描述

这个类图,左侧一列直接是ResultSetHandler接口的实现类,BeanHandler、ScalarHandler、MapHandler、ArrayHandler返回的是单条记录,BeanListHandler,将多条记录转换为List返回。

右侧的实现类是返回多条记录,将多条记录转换为List或者Map对象返回,其元素为Map。这里的抽象类值得学习一下,它将结果集转换为List返回,调用抽象方法handleRow处理每一行数据。源码相当简洁:

public abstract class AbstractListHandler<T>
  implements ResultSetHandler<List<T>>
{
  public List<T> handle(ResultSet rs)
    throws SQLException
  {
    List rows = new ArrayList();
    while (rs.next()) {
      rows.add(handleRow(rs));
    }
    return rows;
  }

  protected abstract T handleRow(ResultSet paramResultSet)
    throws SQLException;
}

此外,KeyedHandler,将结果集转换为Map,每一行以某一列的值为key ,整行的数据作为值存入Map中。所以,如它的名字一样,它提供一个createKey的方法,指定某一列作为结果的key ,每一行结果存入Map中,作为对应key的值。

public Map<K, V> handle(ResultSet rs)
    throws SQLException
  {
    Map result = createMap();
    while (rs.next()) {
      result.put(createKey(rs), createRow(rs));
    }
    return result;
  }

自定义ResultSetHandler

由于最初使用的NoSQL数据库存储数据,所以Java的实体定义过程中,并没有考虑关联表的设计,而且所用到的表都没有特别强烈的依赖关系,所以使用TokuDB数据库后,表结构不变,对于原来类中复杂的字段的存储,直接转换为JSON字符串入库,查询过程中再单独处理该列,转换为Java依赖的对象。

在ORM映射过程中,需要自定义ResultHandler,实现一个简单的Java类的ORM处理如下:

public class MyComplexData {

    /** 编号 */
    private String _id;
    /** 名称 */
    private String name;
    /** 认证服务器列表 */
    private List<String> authServers;
    /** 提正则表达式 */
    private List<String> patterns;
    /** 启用状态 */
    private String status;

    private PersonInfo personInfo;
}

以这样一个类MyComplexData 为类,存储它的authServers、patterns、personInfo这三个属性时,将属性值转换为JSON字符串存储。那么查询操作,需要回转为原来的类型,自定义ResultSetHandler类如下:

public class MyResultSetHandler implements ResultSetHandler<Object>{

    @Override
    public Object handle(ResultSet arg0) throws SQLException {

        List<MyComplexData> result = new ArrayList<MyComplexData>(16);
        Field[] fields = MyComplexData.class.getDeclaredFields();
        while(arg0.next()){
            MyComplexData cur = new MyComplexData();
            for(Field field:fields){
                String name = field.getName();
                Object columnValue = arg0.getObject(name);
                Class columnType = field.getType();
                if(columnValue!=null&& (ArrayList.class==columnType||List.class==columnType)){
                    //数据库存储的是JSON,回转成Java对象
                    List list = JSONObject.parseArray(columnValue.toString(),Object.class);
                    columnValue = list;
                    System.out.println("特殊属性,回转为List");
                }else{
                    //普通属性,直接设置值
                }

                String setter = DbConnectionPool.obtainSetterName(name);
                try {
                    Method method = MyComplexData.class.getMethod(setter, columnType);
                    method.invoke(cur, columnValue);
                } catch (Exception e) {
                 }              
            }

            result.add(cur);
        }

        return result;
    }

}

ORM映射的逻辑是这样的:

1 数据库表的列名称和Java类的各个属性名称一致
2插入过程中,将Integer、Long、String、Short、Character等简单类型之外的其他类型的属性,都转换为JSON字符串,作为参数插入。
3 查询过程中,处理每一条ResultSet,利用反射调用各个列对应的setter方法,
简单属性,直接设值,复杂属性,利用fastjson转换为对应类型的Java对象后,再赋值给当前属性。

启示录

在选择ORM工具的时候,由于类设计的相当复杂,所以最先排斥的就是MyBatis复杂的映射查询操作,不想处理复杂的关联问题。

换一种思路,以JSON格式存储依赖关系之后,再利用dbutils这个工具,接下来的工作就容易多了。我以前读过iBatis的源码,再看dbutils的源码,当前项目中的DAO类的源码也是我写的,在这样的基础上,再写一套ORM代码,三天就完成了。先前特别排斥的换库情绪,也慢慢消失了。

想不到一句话来总结了,唯一的感悟就是:多亏自己平时注意积累,才能在编码的时候能得心应手。还是那句话:认真编码、认真生活!

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

JDBC轻量级封装的工具包Apache DbUtils使用教程

这个工具在JDBC的基础上稍加封装是JDBC的操作更加便捷,在学习使用这个框架的途中你也不需要学习太多的API类,因为一共也才3个部分(3个包)。   1. org.apache.commons...

数据库工具包的使用(commons-dbutils-1.2.jar)--转载之二

另外附加增删除改的代码: 1.使用commons DButils组件对数据库进行查询。 首先使用数据源以及本组件进行数据库的连接,创建QueryRunner类型的对象。 使用数组,对sql语...

dbutils工具包和源文件

  • 2017年03月14日 10:10
  • 791KB
  • 下载

数据库工具包的使用(commons-dbutils-1.2.jar)

朋友你还在为框架着急码?不用了,不会持久性框架照样可以开发高效的代码。如果你对Hibernate不是很了解,你的代码效率也会很烂! 如果你对IBatis不是很了解也不想学习,又想开发高效的项目,那么我...
  • tjcyjd
  • tjcyjd
  • 2012年04月15日 22:24
  • 3517

java--DBUtils数据库操作工具包

O-R Mapping简介 什么是O-R Mapping Object(对象)来映射Ralation(关系,表) 常用O-R Mapping映射工具 Hibernate Commons D...
  • xanlv
  • xanlv
  • 2016年11月22日 11:00
  • 899

xUtils中的dbUtils中,在应用升级的时候修改表结构

我们在做数据缓存的时候经常用到数据库,数据库在进行存储的时候特别灵活也比较简单。虽然好用,但是存在一个问题,就是我们的应用在进行迭代的时候可能随着需求的变化,我们需要对表结构进行修改(一般是添加字段)...

DbUtils应用指南

DbUtils是一个小型的类库,它设计用于使JDBC编程更加方便、简单。JDBC编程中,资源的关闭是显式的,极易导致编程错误,DbUtils把这些清理工作抽象出来,使得程序员编程时仅需要关心真正需要关...

DBUtils应用详解

DBUtils 环境搭建: 1、 复制库文件 c3p0的jar及c3p0-config.xml dbuitls的jar包 mysql驱动包 2、复制并修改DBManager CRID ...

移动应用地图工具包WhirlyGlobe-Maply新建android项目

WhirlyGlobe-Maply是一个基于OpenGL ES、专注移动应用的开源地图工具包,支持ios和android平台,本文以android平台为例。环境:windows7 64位,Androi...

JavaBean和BeanUtils工具包的应用

/**  * 1,IntroSpector内省类-->javaBean(BeanInfo)类: 特殊的Java类  *  * 如果要在两个模块之间传递信息,可以将这些信息封装到一个JavaBean中...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:dbutils工具包分析及应用
举报原因:
原因补充:

(最多只允许输入30个字)