DbUtils并非是什么ORM框架,只是对原始的JDBC进行了一些封装,以便我们少写一些重复代码。就“用”而言,仅仅需要学习QueryRunner类和ResultSetHandler接口就可以了。它的显著特点就是超级轻量级,总代码量目测似乎还不到一万行。

通过一个简单的调用看整体结构

public class TestDbUtils {
private static final QueryRunner RUNNER = new QueryRunner(HikariCPUtils.getDs());
public static void main(String[] args) {
ResultSetHandler<SimpleUser> handler = new BeanHandler<>(SimpleUser.class);
SimpleUser user = null;
try {
user = RUNNER.query("SELECT * FROM simple_user WHERE username=?", handler, "admin123");
} catch (SQLException e) {
e.printStackTrace();
}
System.out.println(user);
}
}

TestDbUtils.java

    /**
* Calls query after checking the parameters to ensure nothing is null.
* @param conn The connection to use for the query call.
* @param closeConn True if the connection should be closed, false otherwise.
* @param sql The SQL statement to execute.
* @param params An array of query replacement parameters. Each row in
* this array is one set of batch replacement values.
* @return The results of the query.
* @throws SQLException If there are database or parameter errors.
*/
private <T> T query(Connection conn, boolean closeConn, String sql, ResultSetHandler<T> rsh, Object... params)
throws SQLException {
if (conn == null) {
throw new SQLException("Null connection");
} if (sql == null) {
if (closeConn) {
close(conn);
}
throw new SQLException("Null SQL statement");
} if (rsh == null) {
if (closeConn) {
close(conn);
}
throw new SQLException("Null ResultSetHandler");
} PreparedStatement stmt = null;
ResultSet rs = null;
T result = null; try {
stmt = this.prepareStatement(conn, sql);
this.fillStatement(stmt, params);
rs = this.wrap(stmt.executeQuery());
result = rsh.handle(rs); } catch (SQLException e) {
this.rethrow(e, sql, params); } finally {
try {
close(rs);
} finally {
close(stmt);
if (closeConn) {
close(conn);
}
}
} return result;
}

private T query(Connection conn, boolean closeConn, String sql, ResultSetHandler rsh, Object... params) throws SQLException

AbstractQueryRunner、RowProcessor、ResultSetHandler<T>是Apache Commons DbUtils里的三大主角,通过继承上述抽象类/实现上述接口可以很方便地对API功能进行定制化。

详细类图参考:http://ju.outofmemory.cn/entry/143920

Examples

官方Examples:http://commons.apache.org/proper/commons-dbutils/examples.html

同步请求的代码在上面已经给出。异步请求的草稿代码如下:

public class DbUtilsSampleDAO {

    private AsyncQueryRunner runner = new AsyncQueryRunner(Executors.newCachedThreadPool());

    public Future<Integer> saveProfile(Profile profile) {
Future<Integer> future;
Connection conn = null;
try {
conn = ConnectionFactory.getConnection();
future = runner.update(conn,
"INSERT ignore INTO `profiles`.`profile` (`username`, `password`, `nickname`) " +
"VALUES (?, ?, ?)", profile.getUsername(), profile.getPassword(), profile.getNickname());
} catch (SQLException e) {
throw new DaoException(e);
} finally {
try {
DbUtils.close(conn);
} catch (SQLException e) {
throw new DaoException(e);
}
}
return future;
} public static void main(String[] args) {
DbUtilsSampleDAO dao = new DbUtilsSampleDAO();
Profile profile = new Profile("myusername", "mypassword", "thisnickname");
Future<Integer> future = dao.saveProfile(profile);
try {
System.out.println(future.get() == 1 ? "更新成功" : "更新失败");
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}

修改JAVA连接数据库#03#中的代码

以下代码同步更新在GitHub:https://github.com/xkfx/web-test-01

主要的几个类如下:

① QueryRunnerProxy.java

package org.sample.webapp.db.queryrunner;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.ResultSetHandler;
import org.sample.webapp.db.connmanager.ConnectionFactory;
import org.sample.webapp.exception.DaoException; import java.sql.SQLException; /**
* 封装DAO层通用代码,不会关闭connection!!!
*/
public class QueryRunnerProxy { private QueryRunnerProxy() {
// Exists to defeat instantiation
} private static QueryRunner runner = new QueryRunner(); public static int update(String sql, Object... param) {
int updates = 0;
try {
updates = runner.update(ConnectionFactory.getConnection(), sql, param);
} catch (SQLException e) {
throw new DaoException(e);
}
return updates;
} public static <T> T query(String sql, ResultSetHandler<T> rsh, Object... params) {
T result = null;
try {
result = runner.query(ConnectionFactory.getConnection(), sql, rsh, params);
} catch (SQLException e) {
throw new DaoException(e);
}
return result;
}
}

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

② RsHandlers.java

package org.sample.webapp.db.queryrunner;

import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.sample.webapp.entity.Profile; /**
* 业务相关,保存各式各样的ResultSetHandler常量
*/
public interface RsHandlers { BeanListHandler<Profile> PROFILE_LIST = new BeanListHandler<>(Profile.class); BeanHandler<Profile> PROFILE = new BeanHandler<>(Profile.class);
}

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

③ ProfileDAOImpl.java 顺便改为enum了,仅是因为觉得这样写表示单例更清晰(后来证明这是一个意义非常有限、自寻麻烦的做法。。)

package org.sample.webapp.dao.impl;

import org.sample.webapp.dao.ProfileDAO;
import org.sample.webapp.db.queryrunner.QueryRunnerProxy;
import org.sample.webapp.db.queryrunner.RsHandlers;
import org.sample.webapp.entity.Profile; import java.util.List; /**
* 该类方法统一抛出DaoException
*/
public enum ProfileDAOImpl implements ProfileDAO { INSTANCE; @Override
public int saveProfile(Profile profile) {
final String sql = "INSERT ignore INTO profile (username, password, nickname) " +
"VALUES (?, ?, ?)"; // 添加ignore出现重复不会抛出异常而是返回0
return QueryRunnerProxy.update(sql, profile.getUsername(), profile.getPassword(), profile.getNickname());
} @Override
public List<Profile> listByNickname(String nickname) {
final String sql = "SELECT profile_id AS id, username, password, nickname, last_online AS lastOnline, gender, birthday, location, joined " +
"FROM profile " +
"WHERE nickname=?";
return QueryRunnerProxy.query(sql, RsHandlers.PROFILE_LIST, nickname);
} @Override
public Profile getByUsername(String username) {
final String sql = "SELECT profile_id AS id, username, password, nickname, last_online AS lastOnline, gender, birthday, location, joined " +
"FROM profile " +
"WHERE username=?"; // TODO 该字符串会反复创建吗?
return QueryRunnerProxy.query(sql, RsHandlers.PROFILE, username);
} @Override
public int updateById(Profile profile) {
final String sql = "UPDATE profile " +
"SET nickname=?, gender=?, birthday=?, location=? " +
"WHERE profile_id=?";
return QueryRunnerProxy.update(sql, profile.getNickname(), profile.getGender() != null ? String.valueOf(profile.getGender()) : null,
profile.getBirthday(), profile.getLocation(), profile.getId());
} @Override
public int updatePassword(String username, String password) {
final String sql = "UPDATE profile " +
"SET password=? " +
"WHERE username=?";
return QueryRunnerProxy.update(sql, password, username);
} @Override
public int updateLastOnline(String username) {
final String sql = "UPDATE profile " +
"SET last_online=CURRENT_TIMESTAMP " +
"WHERE username=?";
return QueryRunnerProxy.update(sql, username);
}
}

后续:

1、把sql常量字符串集中放在一个Interface里。如下:

package org.sample.shop.db.queryrunner;

public interface SQLs {
// item
String ITEM_LIST_BY_UID_AND_STATUS = "SELECT id, user_id AS userId, name, price, status, quantity FROM item WHERE user_id=? AND status=?";
String ITEM_SAVE_ITEM = "INSERT INTO item(user_id, name, price, status, quantity) VALUES (?, ?, ?, ?, ?)";
String ITEM_REMOVE_BY_ID = "DELETE FROM item WHERE id=?";
String ITEM_UPDATE_BY_ID = "UPDATE item SET name=?, price=?, status=?, quantity=? WHERE id=?";
// order
String ORDER_GET_BY_UID = "SELECT id, user_id AS userId, total FROM simple_order WHERE user_id=?";
String ORDER_SAVE_ORDER = "INSERT INTO simple_order(user_id, total) VALUES(?, ?)";
String ORDER_SAVE_ORDER_DETAIL = "INSERT INTO order_detail(order_id, item_id, user_id, quantity, price, status) VALUES(?, ?, ?, ?, ?, ?)";
// order detail
String ORDER_DETAIL_GET_BY_ORDER_ID = "SELECT id, order_id AS orderId, item_id AS itemId, user_id AS userId, quantity, price, status FROM order_detail WHERE order_id=?";
String ORDER_DETAIL_GET_BY_UID = "SELECT id, order_id AS orderId, item_id AS itemId, user_id AS userId, quantity, price, status FROM order_detail WHERE user_id=?";
// user
String USER_GET_BY_USERNAME = "SELECT id, username, password, type FROM simple_user WHERE username=?";
String USER_SAVE_USER = "INSERT INTO simple_user(type, username, password) VALUES (?, ?, ?)";
// transport order
String TRANSPORT_ORDER_SAVE_ORDER = "INSERT INTO transport_order(user_id, order_detail_id, location, status) VALUES (?, ?, ?, ?)";
String TRANSPORT_ORDER_GET_BY_UID = "SELECT id, user_id AS userId, order_detail_id AS detailId, location, status FROM transport_order WHERE user_id=?";
String TRANSPORT_ORDER_GET_BY_DETAIL_ID = "SELECT id, user_id AS userId, order_detail_id AS detailId, location, status FROM transport_order WHERE order_detail_id=?";
String TRANSPORT_ORDER_UPDATE_BY_ID = "UPDATE transport_order SET location=?, status=? WHERE id=?";
}

Java连接数据库 #04# Apache Commons DbUtils的更多相关文章

  1. java JDBC (七) org.apache.commons.dbutils 查询

    package cn.sasa.demo1; import java.sql.Connection; import java.sql.SQLException; import java.util.Li ...

  2. java JDBC (六) org.apache.commons.dbutils 增删改

    dbutils是apache封装了JDBC的工具类,比mysql-connector更方便些 下载地址:http://commons.apache.org/proper/commons-dbutils ...

  3. java.lang.ClassNotFoundException: org.apache.commons.dbutils.QueryRunner

    七月 28, 2017 11:06:33 下午 org.apache.catalina.core.StandardWrapperValve invoke严重: Servlet.service() fo ...

  4. Apache Commons DbUtils 快速上手

    原文出处:http://lavasoft.blog.51cto.com/62575/222771 Hibernate太复杂,iBatis不好用,JDBC代码太垃圾,DBUtils在简单与优美之间取得了 ...

  5. 写一个ORM框架的第一步(Apache Commons DbUtils)

    新一次的内部提升开始了,如果您想写一个框架从Apache Commons DbUtils开始学习是一种不错的选择,我们先学习应用这个小“框架”再把源代码理解,然后写一个属于自己的ORM框架不是梦. 一 ...

  6. 高性能jdbc封装工具 Apache Commons DbUtils 1.6(转载)

    转载自原文地址:http://gao-xianglong.iteye.com/blog/2166444 前言 关于Apache的DbUtils中间件或许了解的人并不多,大部分开发人员在生成环境中更多的 ...

  7. 《笔者带你剖析Apache Commons DbUtils 1.6》(转)

    前言 关于Apache的DbUtils中间件或许了解的人并不多,大部分开发人员在生成环境中更 多的是依靠Hibernate.Ibatis.Spring JDBC.JPA等大厂提供的持久层技术解决方案, ...

  8. 模拟apache commons dbutils 实现自己的BeanListHandler(回调应用)

    首先dbcp相关的jar包和MySQL的驱动包导入到项目中. dbcp.properties配置文件如下,并放到项目根目录下. driverClassName=com.mysql.jdbc.Drive ...

  9. 【java】org.apache.commons.lang3功能示例

    org.apache.commons.lang3功能示例 package com.simple.test; import java.util.Date; import java.util.Iterat ...

随机推荐

  1. 使用Python监控Linux系统

    一.Python编写的监控工具 一.多功能系统资源统计工具dstat 1.dstat介绍 dstat是一个用Python语言实现的多功能系统资源统计工具,用来取代Linux下的vmstat.iosta ...

  2. 日志文件系统syslog,syslog-ng

    日志文件系统syslog,syslog-ng   余二五 2017-11-07 20:37:00 浏览127 评论0 日志 LOG 配置 主机 正则表达式 syslog 表达式 source file ...

  3. syslog-ng应用详解

    syslog-ng应用详解   科技小能手 2017-11-07 02:43:00 浏览136 评论0 日志 LOG 配置 主机 syslog source file varchar 摘要: 最近做一 ...

  4. 《全栈性能Jmeter》-3JMeter体系结构

  5. windows系统上利用putty通过SSH连接亚马逊AWS服务器

    1. 找到在购买亚马逊的AWS服务器时保存的密钥文件(假设为abc.pem). 2.打开PuTTYgen,如下图,点击图中1处的“load”,找到abc.pem文件所在的位置,并选择abc.pem,确 ...

  6. Python的Numpy库简述

    numpy 是 python 的科学计算库import numpy as np 1.使用numpy读取txt文件 # dtype = "str":指定数据格式 # delimite ...

  7. Tensorflow 搭建神经网络及tensorboard可视化

    1. session对话控制 matrix1 = tf.constant([[3,3]]) matrix2 = tf.constant([[2],[2]]) product = tf.matmul(m ...

  8. 基于Jenkins的持续交付方案

    简介 Jenkins是开源的自动化编译.测试.部署的Web应用程序一个持续性交付应用 Jenkins的优势 1.Jenkins在国内的开发者中认可度较高,很多创业公司的自建持续交付系统的选择大部分都是 ...

  9. 使用spring的特殊bean完成分散配置

    1.在使用分散配置时,spring的配置文件applicationContext.xml中写法如下: <!-- 引入db.properties文件, --> <context:pro ...

  10. python中使用rabbitmq消息中间件

    上周一直在研究zeromq,并且也实现了了zeromq在python和ruby之间的通信,但是如果是一个大型的企业级应用,对消息中间件的要求比较高,比如消息的持久化机制以及系统崩溃恢复等等需求,这个时 ...