JDBC框架——DBUtils

JDBC框架——DBUtils



本文包括:

1、DBUtils简介

2、DbUtils类

3、QueryRunner类

4、ResultSetHandler接口

5、使用步骤

1、DbUtils简介

commons-dbutils 是 Apache 组织提供的一个开源

JDBC工具类库,它是对JDBC的简单封装,学习成本极低,并且使用dbutils能极大简化jdbc编码的工作量,创建连接、结果集封装、释放资源,同时也不会影响程序的性能。创建连接、结果集封装、释放资源因此dbutils成为很多不喜欢hibernate的公司的首选。

API介绍:

org.apache.commons.dbutils.QueryRunner --- 核心

org.apache.commons.dbutils.ResultSetHandler --- 结果集封装器

org.apache.commons.dbutils.DbUtils --- 工具类

地址:http://commons.apache.org/proper/commons-dbutils/

学习重点:多看看API,多看看官网的example!

2、DbUtils类

DbUtils :提供如加载驱动、关闭连接、事务提交、回滚等常规工作的工具类,里面的所有方法都是静态的。主要方法如下:

DbUtils类提供了三个重载的关闭方法。这些方法检查所提供的参数是不是NULL,如果不是的话,它们就关闭Connection、Statement和ResultSet。

publicstaticvoidclose(…) throws java.sql.SQLException

这一类"quietly"方法不仅能在Connection、Statement和ResultSet为NULL情况下避免关闭,还能隐藏一些在程序中抛出的SQLException。

publicstaticvoidcloseQuietly(…)

用来提交连接,然后关闭连接,并且在关闭连接时不抛出SQL异常。

publicstaticvoidcommitAndCloseQuietly(Connection conn)

装载并注册JDBC驱动程序,如果成功就返回true。使用该方法,你不需要捕捉这个异常ClassNotFoundException。

publicstaticbooleanloadDriver(java.lang.StringdriverClassName)

3、QueryRunner类

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

QueryRunner类提供了两个构造方法:

默认的构造方法:QueryRunner()

需要一个 javax.sql.DataSource 来作参数的构造方法:QueryRunner(DataSource ds)

注意:构造器需要传入DataSource参数,所以必须要用到连接池,关于JDBC连接池可参考我之前的一篇文章:《JDBC进阶——连接池》。在那篇文章中的JDBCUtils类中没有相应的方法来获得DataSource对象,所以应该在JDBCUtils类中加入如下代码:

// 返回数据库连接池publicstaticDataSourcegetDataSource(){returndataSource;}

常用方法(分为两种情况):

批处理

batch(Connection conn,Stringsql,Object[][] params)// 传递连接批处理batch(Stringsql,Object[][] params)// 不传递连接批处理

查询操作

publicObjectquery(Connection conn,Stringsql, ResultSetHandler rsh,Object... params)publicObjectquery(Stringsql, ResultSetHandler rsh,Object... params)

更新操作

public intupdate(Connectionconn,Stringsql, Object... params)publicintupdate(Stringsql, Object... params)

4、ResultSetHandler接口

该接口用于处理 java.sql.ResultSet,将数据按要求转换为另一种形式。

ResultSetHandler 接口提供了一个单独的方法:

Objecthandle(ResultSetrs){}

ResultSetHandler 接口的实现类(构造方法不唯一,在这里只用最常见的构造方法):

ArrayHandler():把结果集中的第一行数据转成对象数组(存入Object[])。

ArrayListHandler():把结果集中的每一行数据都转成一个对象数组,再存放到List中。

BeanHandler(Classtype):将结果集中的第一行数据封装到一个对应的JavaBean实例中。

BeanListHandler(Classtype):将结果集中的每一行数据都封装到一个对应的JavaBean实例中,存放到List里。

Parameters:

type - The Class that objects returned from handle() are created from.

ColumnListHandler(String columnName/int columnIndex):将结果集中某一列的数据存放到List中。

MapHandler():将结果集中的第一行数据封装到一个Map里,key是列名,value就是对应的值。

MapListHandler():将结果集中的每一行数据都封装到一个Map里,然后再将所有的Map存放到List中。

KeyedHandler(String columnName):将结果集每一行数据保存到一个“小”map中,key为列名,value该列的值,再将所有“小”map对象保存到一个“大”map中 , “大”map中的key为指定列,value为“小”map对象

ScalarHandler(int columnIndex):通常用来保存只有一行一列的结果集。

注意:DBUtils-1.4版本中的 ScalarHandler, ColumnHandler, and KeyedHandler没有泛型!要使用1.5以上的版本。

Release Notes Address :http://commons.apache.org/proper/commons-dbutils/changes-report.html

5、使用步骤

将DBUtils的jar包加入到项目工程的build path中。

对于CUD,有两种不同的情况:

情况一:

如果使用 QueryRunner(DataSource ds) 构造器创建QueryRunner对象,需要使用连接池,如DBCP、C3P0等等,数据库事务交给DBUtils框架进行管理 ----默认情况下每条SQL语句单独一个事务

在这种情况下,使用如下方法:

batch(Stringsql, Object[][]params)  query(Stringsql, ResultSetHandlerrsh, Object...params)  update(Stringsql, Object...params)

demo:

@TestpublicvoidtestDelete()throwsSQLException{      QueryRunner queryRunner =newQueryRunner(JDBCUtils.getDataSource());      String sql ="delete from users where id = ?";      queryRunner.update(sql,3);  }@TestpublicvoidtestUpdate()throwsSQLException{      QueryRunner queryRunner =newQueryRunner(JDBCUtils.getDataSource());      String sql ="update users set password = ? where username = ?";      Object[] param = {"nihao","小明"};      queryRunner.update(sql, param);  }@TestpublicvoidtestInsert()throwsSQLException{// 第一步 创建QueryRunner对象QueryRunner queryRunner =newQueryRunner(JDBCUtils.getDataSource());// 第二步 准备方法参数String sql ="insert into users values(null,?,?,?)";      Object[] param = {"小丽","qwe","xiaoli@itcast.cn"};// 第三步 调用 query / updatequeryRunner.update(sql, param);  }

情况二:

如果使用 QueryRunner() 构造器创建QueryRunner对象 ,需要自己管理事务,因为框架没有连接池无法获得数据库连接。

在这种情况下,要使用传入Connection对象参数的方法:

query(Connection conn,Stringsql, ResultSetHandler rsh, Object...params)  update(Connection conn,Stringsql, Object...params)

demo:

// 事务控制@TestpublicvoidtestTransfer()throwsSQLException {doublemoney =100;StringoutAccount ="aaa";StringinAccount ="bbb";Stringsql1 ="update account set money = money - ? where name= ?";Stringsql2 ="update account set money = money + ? where name= ?";// 传入DataSource的构造器,默认每条SQL语句一个单独事务,而在这里要自己管理业务,所以不合适!// QueryRunner queryRunner = new QueryRunner(JDBCUtils.getDataSource());QueryRunner queryRunner =newQueryRunner();// 不要传递连接池 --- 手动事务管理Connection conn = JDBCUtils.getConnection();      conn.setAutoCommit(false);try{          queryRunner.update(conn, sql1, money, outAccount);// 注意要传入Connection对象的方法// int d = 1 / 0;queryRunner.update(conn, sql2, money, inAccount);          System.out.println("事务提交!");          DbUtils.commitAndCloseQuietly(conn);      }catch(Exception e) {          System.out.println("事务回滚!");          DbUtils.rollbackAndCloseQuietly(conn);          e.printStackTrace();      }  }

对于R,需要用到ResultSetHandler接口,该接口有9大实现类,

publicclass ResultSetHandlerTest {// ScalarHandler 通常用于保存只有一行一列的结果集,例如分组函数@Testpublicvoiddemo9()throwsSQLException {        QueryRunner queryRunner =newQueryRunner(JDBCUtils.getDataSource());Stringsql ="select count(*) from account";longcount = (Long) queryRunner.query(sql,newScalarHandler(1));// 得到结果集的第1列System.out.println(count);    }// KeyedHandler 将结果集每一行数据保存到一个“小”map中,key为列名,value该列的值,再将所有“小”map对象保存到一个“大”map中 , “大”map中的key为指定列,value为“小”map对象@Testpublicvoiddemo8()throwsSQLException {        QueryRunner queryRunner =newQueryRunner(JDBCUtils.getDataSource());Stringsql ="select * from account";        Map>map= queryRunner.query(sql,newKeyedHandler("id"));        System.out.println(map);    }// MapListHandler 将结果集每一行数据保存到map中,key列名 value该列的值 ---- 再将所有map对象保存到List集合中@Testpublicvoiddemo7()throwsSQLException {        QueryRunner queryRunner =newQueryRunner(JDBCUtils.getDataSource());Stringsql ="select * from account";        List> list = queryRunner.query(sql,newMapListHandler());for(Mapmap: list) {            System.out.println(map);        }    }// MapHander 将结果集第一行数据封装到Map集合中,key是列名,value为该列的值@Testpublicvoiddemo6()throwsSQLException {        QueryRunner queryRunner =newQueryRunner(JDBCUtils.getDataSource());Stringsql ="select * from account";        Mapmap= queryRunner.query(sql,newMapHandler());// 列名为String类型,该列的值为Object类型System.out.println(map);    }// ColumnListHandler 获得结果集的某一列,将该列的所有值存入List中@Testpublicvoiddemo5()throwsSQLException {        QueryRunner queryRunner =newQueryRunner(JDBCUtils.getDataSource());Stringsql ="select * from account";// 因为每列类型都不一样,所以用List存储// List list = queryRunner.query(sql,// new ColumnListHandler("name")); // 得到表列名为name的列List list = queryRunner.query(sql,newColumnListHandler(2));// 得到结果集的第2列System.out.println(list);    }// BeanListHander 将结果集每一条数据,转为JavaBean对象,再保存到list集合中@Testpublicvoiddemo4()throwsSQLException {        QueryRunner queryRunner =newQueryRunner(JDBCUtils.getDataSource());Stringsql ="select * from account";        List accounts = queryRunner.query(sql,newBeanListHandler(Account.class));for(Account account : accounts) {            System.out.println(account.getId());            System.out.println(account.getName());            System.out.println(account.getMoney());            System.out.println("----------------");        }    }// BeanHandler 将结果集第一行数据封装到JavaBean对象中@Testpublicvoiddemo3()throwsSQLException {        QueryRunner queryRunner =newQueryRunner(JDBCUtils.getDataSource());Stringsql ="select * from account";// 传入 Account.class字节码文件:为了在方法中 通过反射构造Account对象// 使用BeanHandler注意事项 :数据库中的表列名 与 Bean类中属性 名称一致!!!Account account = queryRunner.query(sql,newBeanHandler(                Account.class));        System.out.println(account.getId());        System.out.println(account.getName());        System.out.println(account.getMoney());    }// ArrayListHandler 将结果集每一行数据保存到List中@Testpublicvoiddemo2()throwsSQLException {        QueryRunner queryRunner =newQueryRunner(JDBCUtils.getDataSource());Stringsql ="select * from account";        List list = queryRunner.query(sql,newArrayListHandler());for(Object[] objects : list) {            System.out.println(Arrays.toString(objects));        }    }// ArrayHandler 将结果集第一行数据保存到Object[]中@Testpublicvoiddemo1()throwsSQLException {// 使用DBUtilsQueryRunner queryRunner =newQueryRunner(JDBCUtils.getDataSource());Stringsql ="select * from account";// 对象数组存储rs第一行数据的所有列Object[] values = queryRunner.query(sql,newArrayHandler());        System.out.println(Arrays.toString(values));    } }

JDBC文集:

Java 与数据库的桥梁——JDBC:http://www.jianshu.com/p/c0acbd18794c

JDBC 进阶——连接池:http://www.jianshu.com/p/ad0ff2961597

JDBC 进阶——元数据:http://www.jianshu.com/p/36d5d76342f1

JDBC框架——DBUtils:http://www.jianshu.com/p/10241754cdd7

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容