觉悟吧,少年!

——认真编码,认真生活!

dbutils工具包分析及应用

背景

项目开发过程中,需要更换数据库,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代码,三天就完成了。先前特别排斥的换库情绪,也慢慢消失了。

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

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wojiushiwo945you/article/details/75307104
文章标签: java dbutils
个人分类: 项目开发
想对作者说点什么? 我来说一句

dbutils工具包和源文件

2017年03月14日 791KB 下载

JDBC连接使用的包与DBUtils工具包

2018年04月16日 4.53MB 下载

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭