一、commons-dbutils简介

commons-dbutils 是 Apache 组织提供的一个开源 JDBC工具类库,它是对JDBC的简单封装,学习成本极低,并且使用dbutils能极大简化jdbc编码的工作量,同时也不会影响程序的性能。因此dbutils成为很多不喜欢hibernate的公司的首选。

  commons-dbutilsAPI介绍:

  • org.apache.commons.dbutils.QueryRunner
  • org.apache.commons.dbutils.ResultSetHandler

  工具类

  • org.apache.commons.dbutils.DbUtils

二、QueryRunner类使用讲解

  该类简单化了SQL查询,它与ResultSetHandler组合在一起使用可以完成大部分的数据库操作,能够大大减少编码量。
  QueryRunner类提供了两个构造方法:

  • 默认的构造方法
  • 需要一个 javax.sql.DataSource 来作参数的构造方法。

2.1、QueryRunner类的主要方法

  public Object query(Connection conn, String sql, Object[] params, ResultSetHandler rsh) throws SQLException:执行一个查询操作,在这个查询中,对象数组中的每个元素值被用来作为查询语句的置换参数。该方法会自行处理 PreparedStatement 和 ResultSet 的创建和关闭。
  public Object query(String sql, Object[] params, ResultSetHandler rsh) throws SQLException: 几乎与第一种方法一样;唯一的不同在于它不将数据库连接提供给方法,并且它是从提供给构造方法的数据源(DataSource) 或使用的setDataSource 方法中重新获得 Connection。
  public Object query(Connection conn, String sql, ResultSetHandler rsh) throws SQLException : 执行一个不需要置换参数的查询操作。
  public int update(Connection conn, String sql, Object[] params) throws SQLException:用来执行一个更新(插入、更新或删除)操作。
  public int update(Connection conn, String sql) throws SQLException:用来执行一个不需要置换参数的更新操作。

2.2、使用QueryRunner类实现CRUD

1.建立测试表:

create table users(
id int primary key auto_increment,
name varchar(40),
password varchar(40),
email varchar(60),
birthday date
);

2.建立JavaBean

 package cn.zy.dbutils;

 import java.util.Date;

 public class User {
private int id;
private String name;
private String password;
private String email;
private Date birthday;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User [birthday=" + birthday + ", email=" + email + ", id=" + id
+ ", name=" + name + ", password=" + password + "]";
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}

3.建立测试类

 package cn.zy.test;

 import java.sql.SQLException;
import java.util.Date;
import java.util.List; import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.junit.Test; import cn.zy.dbutils.User;
import cn.zy.utils.JdbcUtils_C3P0; public class QueryRunnerCRUDTest {
@Test
public void add() throws SQLException{
//将数据源传递给QueryRunner,QueryRunner内部通过数据源获取数据库连接
QueryRunner qr = new QueryRunner(JdbcUtils_C3P0.getDataSource());
String sql = "insert into users(name,password,email,birthday) values(?,?,?,?)";
Object param[] = {"张三","123","zhansan@qq.com",new Date(0)};
qr.update(sql, param);
} @Test
public void delete() throws SQLException{
QueryRunner qr = new QueryRunner(JdbcUtils_C3P0.getDataSource());
String sql = "delete from users where id=?";
qr.update(sql,1);
} @Test
public void update() throws SQLException{
QueryRunner qr = new QueryRunner(JdbcUtils_C3P0.getDataSource());
String sql = "update users set name=? where id=?";
Object param[] = {"王五",3};
qr.update(sql, param);
} @Test
public void find() throws SQLException{
QueryRunner qr = new QueryRunner(JdbcUtils_C3P0.getDataSource());
String sql = "select * from users where id=?";
Object params[] = {2};
User user = (User) qr.query(sql, params, new BeanHandler(User.class));
System.out.println(user);
} @Test
public void getAll() throws SQLException{
QueryRunner qr = new QueryRunner(JdbcUtils_C3P0.getDataSource());
String sql = "select * from users";
List list = (List) qr.query(sql, new BeanListHandler(User.class));
System.out.println(list.size());
} @Test
public void testBatch() throws SQLException{
QueryRunner qr = new QueryRunner(JdbcUtils_C3P0.getDataSource());
String sql = "insert into users(name,password,email,birthday) values(?,?,?,?)";
Object params[][] = new Object[10][];
for (int i=0;i<10;i++){
params[i] = new Object[] { "aa" + i, "123", "aa@sina.com",
new Date() };
}
qr.batch(sql, params);
}
}

三、ResultSetHandler接口使用讲解

  该接口用于处理java.sql.ResultSet,将数据按要求转换为另一种形式。
  ResultSetHandler接口提供了一个单独的方法:Object handle (java.sql.ResultSet .rs)

3.1、ResultSetHandler接口的实现类

  • ArrayHandler:把结果集中的第一行数据转成对象数组。
  • ArrayListHandler:把结果集中的每一行数据都转成一个数组,再存放到List中。
  • BeanHandler:将结果集中的第一行数据封装到一个对应的JavaBean实例中。
  • BeanListHandler:将结果集中的每一行数据都封装到一个对应的JavaBean实例中,存放到List里。
  • ColumnListHandler:将结果集中某一列的数据存放到List中。
  • KeyedHandler(name):将结果集中的每一行数据都封装到一个Map里,再把这些map再存到一个map里,其key为指定的key。
  • MapHandler:将结果集中的第一行数据封装到一个Map里,key是列名,value就是对应的值。
  • MapListHandler:将结果集中的每一行数据都封装到一个Map里,然后再存放到List

Scalar处理器

3.2、测试dbutils各种类型的处理器

 package cn.zy.test;

 import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;
import java.util.Map; import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.ArrayHandler;
import org.apache.commons.dbutils.handlers.ArrayListHandler;
import org.apache.commons.dbutils.handlers.ColumnListHandler;
import org.apache.commons.dbutils.handlers.KeyedHandler;
import org.apache.commons.dbutils.handlers.MapHandler;
import org.apache.commons.dbutils.handlers.MapListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import org.junit.Test; import cn.zy.utils.JdbcUtils_C3P0; public class ResultSetHandlerTest {
@Test
public void testArrayHandler() throws SQLException{
QueryRunner qr = new QueryRunner(JdbcUtils_C3P0.getDataSource());
String sql = "select *from users";
Object result[] = (Object[]) qr.query(sql, new ArrayHandler());
System.out.println(Arrays.asList(result));
} @Test
public void testArrayListHandler() throws SQLException{
QueryRunner qr = new QueryRunner(JdbcUtils_C3P0.getDataSource());
String sql = "select * from users";
List<Object[]> list = (List) qr.query(sql, new ArrayListHandler());
for(Object[] o : list){
System.out.println(Arrays.asList(o));
}
}
@Test
public void testColumnListHandler() throws SQLException{
QueryRunner qr = new QueryRunner(JdbcUtils_C3P0.getDataSource());
String sql = "select * from users";
List list = (List) qr.query(sql, new ColumnListHandler("id"));
System.out.println(list);
} @Test
public void testKeyedHandler() throws Exception{
QueryRunner qr = new QueryRunner(JdbcUtils_C3P0.getDataSource());
String sql = "select * from users";
Map<Integer,Map> map = (Map) qr.query(sql, new KeyedHandler("id"));
for(Map.Entry<Integer, Map> me : map.entrySet()){
int id = me.getKey();
Map<String,Object> innermap = me.getValue();
for(Map.Entry<String, Object> innerme : innermap.entrySet()){
String columnName = innerme.getKey();
Object value = innerme.getValue();
System.out.println(columnName + "=" + value);
}
System.out.println("----------------");
}
} @Test
public void testMapHandler() throws SQLException{
QueryRunner qr = new QueryRunner(JdbcUtils_C3P0.getDataSource());
String sql = "select * from users";
Map<String,Object> map = (Map) qr.query(sql, new MapHandler());
for(Map.Entry<String, Object> me : map.entrySet()){
System.out.println(me.getKey() + "=" + me.getValue());
}
} @Test
public void testMapListHandler() throws SQLException{
QueryRunner qr = new QueryRunner(JdbcUtils_C3P0.getDataSource());
String sql = "select * from users";
List<Map> list = (List) qr.query(sql, new MapListHandler());
for(Map<String,Object> map :list){
for(Map.Entry<String, Object> me : map.entrySet())
System.out.println(me.getKey() + "=" + me.getValue());
}
} @Test
public void testScalarHandler() throws SQLException{
QueryRunner qr = new QueryRunner(JdbcUtils_C3P0.getDataSource());
String sql = "select count(*) from users";
int count = ((Long)qr.query(sql, new ScalarHandler(1))).intValue();
System.out.println(count);
} }

依次返回:

====================================

====================================

====================================

+++++++++++++++++++++++++++++++++++

===================================

++++++++++++++++++++++++++++++++++

三、DbUtils类使用讲解

  DbUtils :提供如关闭连接、装载JDBC驱动程序等常规工作的工具类,里面的所有方法都是静态的。主要方法如下:
  public static void close(…) throws java.sql.SQLException: DbUtils类提供了三个重载的关闭方法。这些方法检查所提供的参数是不是NULL,如果不是的话,它们就关闭Connection、Statement和ResultSet。
  public static void closeQuietly(…): 这一类方法不仅能在Connection、Statement和ResultSet为NULL情况下避免关闭,还能隐藏一些在程序中抛出的SQLEeception。
  public static void commitAndCloseQuietly(Connection conn): 用来提交连接,然后关闭连接,并且在关闭连接时不抛出SQL异常。 
  public static boolean loadDriver(java.lang.String driverClassName):这一方装载并注册JDBC驱动程序,如果成功就返回true。使用该方法,你不需要捕捉这个异常ClassNotFoundException。

四、JDBC开发中的事务处理

4.1、在业务层(BusinessService)处理事务

建立表:

CREATE TABLE account(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(40),
money FLOAT
); INSERT INTO account(NAME,money) VALUES('A',1000);
INSERT INTO account(NAME,money) VALUES('B',1000);
INSERT INTO account(NAME,money) VALUES('C',1000);

domain层

 package cn.zy.domain;

 import java.util.Date;

 public class Account {
private int id;
private String name;
private Float money;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Account [id=" + id + ", money=" + money + ", name=" + name
+ "]";
}
public void setName(String name) {
this.name = name;
}
public Float getMoney() {
return money;
}
public void setMoney(Float money) {
this.money = money;
}
public Account(int id, String name, Float money) {
super();
this.id = id;
this.name = name;
this.money = money;
}
public Account() {
super();
} }

写一个Dao类进行进行CURD操作

 package cn.zy.dao;

 import java.sql.Connection;
import java.sql.SQLException;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import cn.zy.domain.Account; public class AccountDao { //接受service层传递过来的Connection对象
private Connection conn = null; public AccountDao(Connection conn){
this.conn = conn;
}
public AccountDao(){ } public void update(Account account) throws SQLException{
QueryRunner qr = new QueryRunner();
String sql = "update account set name=?,money=? where id=?";
Object params[] = {account.getName(),account.getMoney(),account.getId()}; //使用service层传递过来的Connection对象操作数据库
qr.update(conn, sql, params);
System.out.println("更新成功");
} public Account find(int id) throws SQLException{
QueryRunner qr = new QueryRunner();
String sql = "select * from account where id=?";
//使用service层传递过来的Connection对象操作数据库
return (Account) qr.query(conn,sql, id, new BeanHandler(Account.class)); } }

在业务层实现转账

package cn.zy.service;

import java.sql.Connection;
import java.sql.SQLException;
import cn.zy.dao.AccountDao;
import zn.zy.domain.Account;
import zn.zy.util.JdbcUtils; /**
* @ClassName: AccountService
* @Description: 业务逻辑处理层
*/
public class AccountService { /**
* @Method: transfer
* @Description:这个方法是用来处理两个用户之间的转账业务
* @param sourceid
* @param tartgetid
* @param money
* @throws SQLException
*/
public void transfer(int sourceid,int tartgetid,float money) throws SQLException{
Connection conn = null;
try{
//获取数据库连接
conn = JdbcUtils.getConnection();
//开启事务
conn.setAutoCommit(false);
//将获取到的Connection传递给AccountDao,保证dao层使用的是同一个Connection对象操作数据库
AccountDao dao = new AccountDao(conn);
Account source = dao.find(sourceid);
Account target = dao.find(tartgetid); source.setMoney(source.getMoney()-money);
target.setMoney(target.getMoney()+money); dao.update(source);
//模拟程序出现异常让事务回滚
int x = 1/0;
dao.update(target);
//提交事务
conn.commit();
}catch (Exception e) {
e.printStackTrace();
//出现异常之后就回滚事务
conn.rollback();
}finally{
conn.close();
}
}
}

测试:

 package cn.zy.test;

 import java.sql.SQLException;
import org.junit.Test;
import cn.zy.service.AccountService; public class AccountServiceTest {
@Test
public void fun() throws SQLException{
AccountService service = new AccountService();
service.transfer(1, 2, 100f);
}
}

4.2、使用ThreadLocal进行更加优雅的事务处理

上面的在businessService层这种处理事务的方式依然不够优雅,为了能够让事务处理更加优雅,我们使用ThreadLocal类进行改造,ThreadLocal一个容器,向这个容器存储的对象,在当前线程范围内都可以取得出来,向ThreadLocal里面存东西就是向它里面的Map存东西的,然后ThreadLocal把这个Map挂到当前的线程底下,这样Map就只属于这个线程了

ThreadLocal类的使用范例如下:

 package me.gacl.test;

 public class ThreadLocalTest {

     public static void main(String[] args) {
//得到程序运行时的当前线程
Thread currentThread = Thread.currentThread();
System.out.println(currentThread);
//ThreadLocal一个容器,向这个容器存储的对象,在当前线程范围内都可以取得出来
ThreadLocal<String> t = new ThreadLocal<String>();
//把某个对象绑定到当前线程上 对象以键值对的形式存储到一个Map集合中,对象的的key是当前的线程,如: map(currentThread,"aaa")
t.set("aaa");
//获取绑定到当前线程中的对象
String value = t.get();
//输出value的值是aaa
System.out.println(value);
}
}

使用使用ThreadLocal类进行改造数据库连接工具类JdbcUtils,改造后的代码如下:

 package cn.zy.utils;

 import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource; public class JdbcUtils_C3P0_v2 {
private static ComboPooledDataSource ds = null;
//使用ThreadLoacal存储当前线程中的Connection对象
private static ThreadLocal<Connection> threadLocal =new ThreadLocal<Connection>(); //在静态块中创建连接池
static{
try {
//使用C3P0的命名配置来创建数据源
ds = new ComboPooledDataSource("MySQL");
} catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
} /*
* 从数据源中获取数据库连接
*/
public static Connection getConnection() throws SQLException{
//从当前线程中获取数据库连接
Connection conn = threadLocal.get();
if(conn==null){
//从数据源中获取连接
conn = ds.getConnection();
//将conn绑定到当前线程
threadLocal.set(conn);
}
return conn;
} /*
* 开启事务
*/
public static void startTransaction(){
try {
Connection conn = threadLocal.get();
if(conn==null){
conn = getConnection();
//把conn绑定到当前线程上
threadLocal.set(conn);
}
//开启事务
conn.setAutoCommit(false);
} catch (Exception e) {
throw new RuntimeException(e);
}
} /*
* 回滚事务
*/
public static void rollback(){
try {
Connection conn = threadLocal.get();
if(conn!=null){
//回滚事务
conn.rollback();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
} /*
* 提交事务
*/
public static void commit(){
try {
Connection conn = threadLocal.get();
if(conn!=null){
//提交事务
conn.commit();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
} /*
* 关闭数据库连接
*/
public static void close(){
try {
//从当前线程获取连接
Connection conn = threadLocal.get();
if(conn!=null){
conn.close();
//从当前线程接解除定
threadLocal.remove();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
} /*
* 获取数据源
*/
public static DataSource getDataSource(){
return ds;
}
}

对AccountDao进行改造,数据库连接对象不再需要service层传递过来,而是直接从JdbcUtils2提供的getConnection方法去获取,改造后的AccountDao如下:

 package cn.zy.dao;

 import java.sql.Connection;
import java.sql.SQLException;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import cn.zy.domain.Account;
import cn.zy.utils.JdbcUtils_C3P0_v2; public class AccountDao { public void update(Account account) throws SQLException{
QueryRunner qr = new QueryRunner();
String sql = "update account set name=?,money=? where id=?";
Object params[] = {account.getName(),account.getMoney(),account.getId()};
//JdbcUtils2.getConnection()获取当前线程中的Connection对象
qr.update(JdbcUtils_C3P0_v2.getConnection(), sql, params);
} public Account find(int id) throws SQLException{
QueryRunner qr = new QueryRunner();
String sql = "select * from account where id=?";
//JdbcUtils2.getConnection()获取当前线程中的Connection对象
return (Account) qr.query(JdbcUtils_C3P0_v2.getConnection(),sql, id, new BeanHandler(Account.class));
} }

对AccountService进行改造,service层不再需要传递数据库连接Connection给Dao层,改造后的AccountService如下:

 package cn.zy.service;

 import java.sql.Connection;
import java.sql.SQLException;
import cn.zy.dao.AccountDao;
import cn.zy.domain.Account;
import cn.zy.utils.JdbcUtils_C3P0;
import cn.zy.utils.JdbcUtils_C3P0_v2; public class AccountService {
public void transfer(int sourceid,int targetid,float money) throws SQLException{
Connection conn = null;
try {
//开启事务
JdbcUtils_C3P0_v2.startTransaction();
AccountDao dao = new AccountDao(); Account source = dao.find(sourceid);
Account target = dao.find(targetid); //转账
source.setMoney(source.getMoney()-money);
target.setMoney(target.getMoney()+money);
dao.update(source);
dao.update(target);
//提交事务
JdbcUtils_C3P0_v2.commit();
} catch (Exception e) {
e.printStackTrace();
//出现异常之后就回滚事务
JdbcUtils_C3P0_v2.rollback();
}finally{
//关闭数据库连接
JdbcUtils_C3P0_v2.close();
}
} }

这样在service层对事务的处理看起来就更加优雅了。ThreadLocal类在开发中使用得是比较多的,程序运行中产生的数据要想在一个线程范围内共享,只需要把数据使用ThreadLocal进行存储即可

JavaWeb学习总结(十四)--Apache的DBUtils的更多相关文章

  1. JavaWeb学习 (二十四)————Filter(过滤器)常见应用

    一.统一全站字符编码 通过配置参数charset指明使用何种字符编码,以处理Html Form请求参数的中文问题 1 package me.gacl.web.filter; 2 3 import ja ...

  2. javaweb学习总结(十四)——JSP原理

    一.什么是JSP? JSP全称是Java Server Pages,它和servle技术一样,都是SUN公司定义的一种用于开发动态web资源的技术. JSP这门技术的最大的特点在于,写jsp就像在写h ...

  3. javaweb学习总结(十四)——JSP原理(转)

    一.什么是JSP? JSP全称是Java Server Pages,它和servle技术一样,都是SUN公司定义的一种用于开发动态web资源的技术. JSP这门技术的最大的特点在于,写jsp就像在写h ...

  4. javaweb学习总结十四(xml约束之Schema)

    一:schema约束简单介绍 1:xml Schema的定义以及优缺点 2:xml schema入门 3:命名空间 这里http://www.itcast.cn 并没有什么具体的意义,只是命名而已. ...

  5. python3.4学习笔记(十四) 网络爬虫实例代码,抓取新浪爱彩双色球开奖数据实例

    python3.4学习笔记(十四) 网络爬虫实例代码,抓取新浪爱彩双色球开奖数据实例 新浪爱彩双色球开奖数据URL:http://zst.aicai.com/ssq/openInfo/ 最终输出结果格 ...

  6. Linux学习之十四、管线命令

    Linux学习之十四.管线命令 地址:http://vbird.dic.ksu.edu.tw/linux_basic/0320bash_6.php

  7. 风炫安全WEB安全学习第二十四节课 利用XSS钓鱼攻击

    风炫安全WEB安全学习第二十四节课 利用XSS钓鱼攻击 XSS钓鱼攻击 HTTP Basic Authentication认证 大家在登录网站的时候,大部分时候是通过一个表单提交登录信息. 但是有时候 ...

  8. JavaWeb学习总结(四):Servlet开发(二)

    一.ServletConfig讲解 1.1.配置Servlet初始化参数 在Servlet的配置文件web.xml中,可以使用一个或多个<init-param>标签为servlet配置一些 ...

  9. (C/C++学习笔记) 十四. 动态分配

    十四. 动态分配 ● C语言实现动态数组 C语言实现动态数组,克服静态数组大小固定的缺陷 C语言中,数组长度必须在创建数组时指定,并且只能是一个常数,不能是变量.一旦定义了一个数组,系统将为它分配一个 ...

  10. linux 学习第十四天(Apache安装、基于ip、基于域名、基于端口配置)

    一.虚拟主机 A.基于IP地址  B.基于域名  C.基于端口号 复习yum仓库挂载 mkdir /media/cdrom mount /dev/cdrom /media/cdrom/ vim /et ...

随机推荐

  1. java 面试每日一题

    题目:一球从100米高度自由落下,每次落地后反跳回原高度的一半:再落下,求它在 第10次落地时,共经过多少米?第10次反弹多高? import java.util.Scanner; public cl ...

  2. 用canvas画时钟

    效果图在博客首页上. html: <canvas id="canvas" >Your browser does not support canvas</canva ...

  3. cookie学习

    cookie是储存于访问者的计算机中的变量,每当同一台计算机通过浏览器请求某个页面时,就会发送这个cookie,可以使用javascript来创建和取回cookie的值. 创建和存储cookie 首先 ...

  4. JAVA基础知识之Collections工具类

    排序操作 Collections提供以下方法对List进行排序操作 void reverse(List list):反转 void shuffle(List list),随机排序 void sort( ...

  5. 2007 Asia - Nanjing F题,字典树

    题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&category=2 ...

  6. Web项目后台测试流程

    1. 本地下载项目源码 1. Git clone项目代码到本地(本地项目代码1)并fetch: 2. Switch到master分支: 3. Create测试分支(例如:test1)并勾选“Switc ...

  7. Statement和PreparedStatement批量更新

    优势:1.节省传递时间. 2.并发处理. PreparedStatement: 1) addBatch()将一组参数添加到PreparedStatement对象内部. 2) executeBatch( ...

  8. Cheatsheet: 2014 08.01 ~ 08.31

    Web Slow Server? This is the Flow Chart You're Looking For A Strolll Through Node: Introduction .NET ...

  9. Create Stacked Canvas to Scroll Horizontal Tabular Data Blocks In Oracle Forms

    In this tutorial you will learn to create horizontal scrollable tabular or detail data block by usin ...

  10. 使用OmniGraffle制作原型图

    原型图设计是一个艺术创作的过程,所以我们应当使用能够提高工作效率.激发创作灵感的工具,让工具为创作服务,而不是为创作去学习如何使用工具.从这一点上说,我觉得Mac下的很多软件做的非常好,OmniGra ...