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代码,三天就完成了。先前特别排斥的换库情绪,也慢慢消失了。

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

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

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

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

DBUtils工具类

DBUtils工具类
  • lfh15732626246
  • lfh15732626246
  • 2016年12月27日 13:39
  • 1114

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

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

DBUtils原理及基本使用

首先我们通过一个基本的演示来了解一下DBUtils的基本原理 public class UseDButils { public static void main(String[] args) {...
  • c1523456
  • c1523456
  • 2017年04月15日 17:39
  • 276

使用DBUtils第三方工具类,实现MySQL数据库的增删改查

DBUtuls第三方工具类使用到的有: 1.ResultSetHandler接口 结果集处理接口 2.QueryRunner类 完成数据库的增/删/改/查 3.DbUtils类 ...
  • aongi
  • aongi
  • 2017年05月02日 17:35
  • 643

编程语言分析及其应用

编程语言分析及其应用 主要要求实现以下三个部分: Lisp格式到C格式的转换 Lisp格式表达式的计算 Lisp格式表达式的类型检测 实现语言:C++...
  • ys676623
  • ys676623
  • 2017年06月16日 22:15
  • 214

DButils工具类库的使用

最近在做课程要求做的java web应用,经队友XM的介绍,开始接触DButils这个工具类库,没接触这个之前觉得牵扯到数据库的一句一句的写也没那么麻烦,但用过这之后真心感觉,之前我干嘛那么累自己,所...
  • violet_echo_0908
  • violet_echo_0908
  • 2015年10月29日 23:17
  • 2099

DbUtils工具的使用

DbUtils工具的使用DbUtils工具的使用 概述 核心API 一个例子概述DbUtils是由Apache软件基金会提供的一个开源的Java应用程序连接数据库的工具,该工具是对JDBC协议的一种封...
  • jpzhu16
  • jpzhu16
  • 2016年06月05日 16:36
  • 2218

day17配置文件+dbUtils工具包

Properties配置文件 duUtils包 QueryRunner接口(八大实现类)
  • kevinr1990
  • kevinr1990
  • 2017年10月28日 21:35
  • 76

数据库查询工具包 DbUtils

原则上这不能说是一个持久层框架,它提供了一些Jdbc的操作封装来简化数据查询和记录读取操作。本站就是采用这个项目来读写数据库,代码非常简洁,如果你厌烦了Hibernate的庞大,不妨可以试试——DbU...
  • e_wsq
  • e_wsq
  • 2012年06月19日 11:03
  • 382
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:dbutils工具包分析及应用
举报原因:
原因补充:

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