《笔者带你剖析Apache Commons DbUtils 1.6》
前言
关于Apache的DbUtils中间件或许了解的人并不多,大部分开发人员在生成环境中更多的是依靠Hibernate、Ibatis、Spring JDBC、JPA等大厂提供的持久层技术解决方案,或者是企业内部自己研发的持久层技术。但无论如何,使用这些技术的初衷和本质都是为了能够减少企业开发成本,提高生产效率,降低耦合。
放眼企业级项目,Hibernate等ORM产品是首选,而互联网领域,大部分开发人员往往并不会在生产环境中上这些ORM技术,原因很简单,要的就是效率,其次都不重要。对于刚接触SQL和JDBC的开发人员,最引以为傲的就是希望能够在日后编写复杂的SQL语句,以及会使用诸如Hibernate、Ibatis等第三方持久层技术,并且极力的撇清与传统JDBC技术的关系,但笔者不得不认为,这是一种普遍业界存在的“病态”!
如果是企业级的项目,尤其是跟金融相关的业务,SQL语句或许会非常复杂,并且关联着事物。但互联网项目却并非如此,在互联网项目中,看你牛不牛逼并不是取决于你能否写出一条复杂的SQL语句,而是看你能否将原本一条复杂的SQL语句拆散成单条SQL,一句一句的执行;并且脱离Hibernate等ORM产品后,能否使用传统的JDBC技术完成一条简单的CRUD操作,这才是牛逼!是的,你没有听错,互联网确确实实就是这么玩,还原最本质的东西,才是追求性能的不二选择。
笔者本章不会提及垂直分库、水平分区等数据库概念,以及数据路由中间件等技术(请阅读笔者博文《剖析淘宝TDDL—Matrix层分库分表实现》),因为这些内容与本章内容无关,但间接来看,笔者之前提及的单条SQL、使用JDBC完成基本的CRUD操作就可以在最大程度上满足一个互联网场景的持久层操作。以Hibernate为例,简单来说需要经历HQL->SQL->DBMS等编译过程,中间还冗余着缓存、对象等开销,希望大家记住,封装层次越高,性能越低!这个是无可争议的事实。笔者希望大家接下来,暂时“忘记”掉你所会的持久层技术,耐心的听笔者为你介绍Apache的DbUtils技术,或许你会有意想不到的收获。
目录
一、Apache Commons DbUtils简介;
二、下载与安装DbUtils;
三、使用DbUtils完成CRUD操作;
四、C3P0连接池集成DbUtils;
五、常用包、类讲解;
六、自动封装结果集;
七、事物管理;
一、Apache Commons DbUtils简介;
Apache的DbUtils工具是一个轻量级的持久层解决方案,天生为性能而生,它简单的对JDBC进行了必要的操作封装,让开发人员能够以一种高级API的方式使用JDBC技术完成原本复杂的CRUD操作。换句话说,DbUtils天生就不是一个复杂的技术,它只是一个简单的JDBC上层封装,对开发人员而言,大概只需半小时就能够完全掌握DbUtils技术的使用,是的,它就是这么简单与方便,它是互联网项目的宠儿,选择DbUtils技术作为持久层的解决方案,或许能够让你从原本复杂的Hibernate操作中解脱出来,或者是你觉得Ibatis不够好用,DbUtils也是你选择的理由之一。总之,使用它,你将会感到惊艳,它是如此的简单和干净,如此的纯粹和高效!并且DbUtils是采用商业友好的开源协议,大家甚至可以下载它的源码,进行二次开发,以此满足企业自身的需要。
二、下载与安装DbUtils;
当大家对DbUtils的项目背景有所了解后,接下来本节内容笔者将会告诉你它的下载和安装。大家可以登录http://commons.apache.org/站点下载DbUtils工具的最新版本,笔者使用的版本为1.6.0,在此大家需要注意,为了避免在开发过程中出现异常,建议大家下载、使用与笔者本篇博文一致的版本。
当大家成功下载好DbUtils相关的构件后,我们可以将其添加到项目中的ClassPath目录下,当然笔者后续小节会提及DbUtils与C3P0连接池的集成,因此,大家最好将C3P0所需的构件以及数据库驱动(笔者使用Mysql)一起添加到项目中。使用DbUtils时关联的构件,如下所示:
3、使用DbUtils完成CRUD操作;
废话不多说,使用DbUtils操作数据库之前,首先要做的事情就是获取Connection。那么为了方便,笔者使用硬编码的方式将数据源的配置信息coding在代码中(生产环境中,有可能是配置在项目的配置文件中、数据库中、Diamond中等),如下所示:
/** * 数据源信息 * * @author gaoxianglong */ public class ConnectionManager { public static Connection getConnection() { Connection conn = null; try { Class.forName("com.mysql.jdbc.Driver"); conn = DriverManager.getConnection( "jdbc:mysql://ip:port/dbName", "userName", "passWord"); } catch (Exception e) { e.printStackTrace(); } return conn; } }
当编写好ConnectionManager之后,接下来要做的事情就是获取Connection,然后就能够使用DbUtils进行CRUD操作了。或许细心的读者已经发现,使用DbUtils其实是非常简单的,需要会的不多,仅仅只需要掌握JDBC操作以及简单的CRUD操作即可(互联网场景下同样也是这么要求)。
@Test public void testInsert() { final String SQL = "insert into test_1 values(?, ?)"; try { if (null == conn || conn.isClosed()) conn = ConnectionManager.getConnection2(); int result = new QueryRunner().update(conn, SQL, new Object[] { "JohnGao1", "123" }); if (0 < result) System.out.println("数据插入成功..."); } catch (Exception e) { e.printStackTrace(); } finally { close(conn); } } @Test public void testUpdate() { final String SQL = "update test_1 set password= ? where username = ?"; try { if (null == conn || conn.isClosed()) conn = ConnectionManager.getConnection(); int result = new QueryRunner().update(conn, SQL, new Object[] { "321", "JohnGao1" }); if (0 < result) System.out.println("数据更新成功..."); } catch (Exception e) { e.printStackTrace(); } finally { close(conn); } } @Test public void testDelete() { final String SQL = "delete from test_1 where username like ?"; try { if (null == conn || conn.isClosed()) conn = ConnectionManager.getConnection(); int result = new QueryRunner().update(conn, SQL, "%JohnGao%"); if (0 < result) System.out.println("数据删除成功..."); } catch (Exception e) { e.printStackTrace(); } finally { close(conn); } } @Test public void testQuery() { final String SQL = "select * from test_1"; try { if (null == conn || conn.isClosed()) conn = ConnectionManager.getConnection(); Test_1Bean test1Bean = new QueryRunner().query(conn, SQL, new BeanHandler(Test_1Bean.class)); if (null != test1Bean) { System.out.println(test1Bean.getUsername()); System.out.println(test1Bean.getPassword()); } } catch (Exception e) { e.printStackTrace(); } finally { close(conn); } }
四、C3P0连接池集成DbUtils;
在生产环境中,开发人员在对数据库进行CRUD操作的时候,由于数据库的链接是有限的,因此不得不使用连接池来实现资源复用,以此降低数据库的性能瓶颈(尽管这么说有些不太友好,因为并发环境下,单靠连接池是不能够解决问题的,而常用的方案更多是诸如Redis之类的内存数据库抗住70%传统DBMS数据的受访压力、数据库先做垂直分库,再做水平分区,当然Master/Sleave是必不可少的,经过这些步骤之后,才能够说基本上解决了理论上可能出现的数据库在高并发环境下的瓶颈)。
废话不多说,在之前的ConnectionManager中添加进连接池相关的代码,当然为了方便,笔者同样还是使用硬编码的方式,如下所示:
public static ComboPooledDataSource dataSource; static { try { dataSource = new ComboPooledDataSource(); dataSource.setUser("userName"); dataSource.setPassword("passWord"); dataSource.setJdbcUrl("jdbc:mysql://ip:port/dbName"); dataSource.setDriverClass("com.mysql.jdbc.Driver"); dataSource.setInitialPoolSize(10); dataSource.setMinPoolSize(5); dataSource.setMaxPoolSize(50); dataSource.setMaxStatements(100); dataSource.setMaxIdleTime(60); } catch (Exception e) { e.printStackTrace(); } } /** * 从连接池中获取数据源链接 * * @author gaoxianglong * * @return Connection 数据源链接 */ public static Connection getConnection2() { Connection conn = null; if (null != dataSource) { try { conn = dataSource.getConnection(); } catch (SQLException e) { e.printStackTrace(); } } return conn; }
当成功在ConnectionManager中添加好所需的C3P0连接池配置后,接下来要做的事情就是考虑如何使用C3P0与DbUtils之间的集成。其实最简单的做法就是直接将之前获取Connection的getConnection()方法更换为上述代码中的getConnection2()即可,同样可以使用在创建QueryRunner实例时,将数据源的DataSource传递过去,这样即可避免在执行CRUD操作时,还需要在方法中指明Connection。
当然究竟应该怎么做,完全取决于你自己,如果希望方便,那么笔者建议你在创建QueryRunner实例时,直接将C3P0的DataSource传递过去,但这样做的弊端很明显,如果在特殊的场景下,需要手动控制事物时,那么这种操作是极其不便的,因为Connection并不可控。那么为了解决事物控制的问题,当然是Connection可控最好。
五、常用包、类讲解;
相信大家已经从上述DbUtils的CRUD示例中发现了QueryRunner的身影,那么笔者接下来就将会针对DbUtils中诸如QueryRunner等常用类型进行深入讲解。
在DbUtils中,最常用的3个包为org.apache.commons.dbutils、org.apache.commons.dbutils.handlers以及org.apache.commons.dbutils.wrappers。
org.apache.commons.dbutils包下的常用类,如下所示:
1、DbUtils : 提供如关闭连接、装载 JDBC 驱动程序等常规工作的工具类;
2、QueryRunner : 该类简单化了 SQL 查询,它常与与 ResultSetHandler 组合在一起使用;
org.apache.commons.dbutils.handlers包下的常用类,如下所示:
1、ArrayHandler :将ResultSet中第一行的数据转化成对象数组;
2、ArrayListHandler:将ResultSet中所有的数据转化成List,List中存放的是Object[];
3、BeanHandler :将ResultSet中第一行的数据转化成类对象;
4、BeanListHandler :将ResultSet中所有的数据转化成List,List中存放的是类对象;
5、ColumnListHandler :将ResultSet中某一列的数据存成List,List中存放的是Object对象;
6、KeyedHandler :将ResultSet中存成映射,key为某一列对应为Map。Map中存放的是数据;
7、MapHandler :将ResultSet中第一行的数据存成Map映射;
8、MapListHandler :将ResultSet中所有的数据存成List。List中存放的是Map;
9、ScalarHandler :将ResultSet中一条记录的其中某一列的数据存成Object;
org.apache.commons.dbutils.wrappers包下的常用类,如下所示:
1、SqlNullCheckedResultSet :该类是用来对sql语句执行完成之后的的数值进行null的替换;
2、StringTrimmedResultSet :去除ResultSet中中字段的左右空格;
六、自动封装结果集;
在org.apache.commons.dbutils.handlers包下的类型,大部分都是与查询结果集相关的。试想一下,利用传统的JDBC进行查询时,返回的数据我们需要对ResultSet进行迭代,这是相当麻烦的,且不利于维护,因为我们需要手动编写与之相关的数据封装。但是使用DbUtils之后,我们要做的事情仅仅只是告诉DbUtils我们需要什么样的数据即可,关于数据封装这种通用的控制逻辑,则无需开发人员参与,这极大的节省了开发人员的时间,提升了生产效率。
简单来说,笔者在开发过程中使用最广泛的就是BeanListHandler以及MapListHandler 封装的结果集。简单来说,BeanListHandler将会查询后的数据封装到一个对应的POJO中(可以看做是一个无状态的实体Bean),MapListHandler 会将查询后的数据封装为一个List,List中存储的就是一个个的Map集合,通过key-value的方式获取封装后的数据集。先来看看MapListHandler 的使用,如下所示:
@Test public void testQuery4() { final String SQL = "select * from test_1 where username like ?"; try { if (null == conn || conn.isClosed()) conn = ConnectionManager.getConnection2(); List<Map<String, Object>> values = new QueryRunner().query(conn, SQL, new Object[] { "%JohnGao%" }, new MapListHandler()); if (null != values) { for (int i = 0; i < values.size(); i++) { Map<String, Object> map = values.get(i); System.out.println(map.get("username")); System.out.println(map.get("password")); } } } catch (Exception e) { e.printStackTrace(); } finally { close(conn); } }
如果你喜欢类似于实体Bean的操作方式,那么BeanListHandler无疑使最好的选择。一旦我们使用BeanListHandler作为数据返回后的结果集封装,那么DbUtils便会将查询后的结果集一个字段一个字段的映射到指定的POJO中,当然前提就是字段名称是必须一致的,否则DbUtils将无法完成数据封装。BeanListHandler的使用示例,如下所示:
@Test public void testQuery3() { final String SQL = "select * from test_1 where username like ?"; try { if (null == conn || conn.isClosed()) conn = ConnectionManager.getConnection(); List<Test_1Bean> test1Beans = new QueryRunner().query(conn, SQL, new Object[] { "%JohnGao%" }, new BeanListHandler( Test_1Bean.class)); if (null != test1Beans) { for (Test_1Bean test1Bean : test1Beans) { System.out.println(test1Bean.getUsername()); System.out.println(test1Bean.getPassword()); } } } catch (Exception e) { e.printStackTrace(); } finally { close(conn); } }
在此大家需要注意,为了方便演示,笔者在此并没有提供对应的POJO。如果有需要,大家可以编写一个与数据库表字段相同的POJO来完成查询结果集的字段映射封装操作。
七、事物管理;
说起事物管理,这其实是一个非常复杂与繁琐,且是最容易出错的场景,尤其是在手动管理事物操作上。当然本节所提及的事物管理仍然是建立在基于手动管理的事物操作上。对于JDBC操作,如果希望事物不要手动提交,那么在获取Connection的时候,一定需要将设置conn.setAutoCommit(false);这样一来事物就不会自动进行提交,当我们手动执行conn.commit()方法的时候,事物才会进行提交。这种方式对于DbUtils其实是一样的,之前也说过,DbUtils仅仅只是对JDBC做了一个轻量级的上层封装,那么必然可以和JDBC进行混用,一旦我们在程序中设定了事物后,接下来的事物管理操作就依赖与开发人员自身了,DbUtils将不会再参与事物的管理。
对于大多数开发人员而言,事物控制的不好,将会导致业务出现问题,脏数据等情况是非常常见的,但从另一个层面来说,手动的事物管理其实是最灵活和方便的。在此需要提醒大家,如果是使用Mysql数据库,只有将数据库引擎设置为InnoDB后,才会支持事物!
最后笔者在啰嗦一下,使用完资源后,我们一定要记得及时释放掉资源,以此避免无用资源长时间挂起。那么在DbUtils中,你将有2种方式结束掉Connection,第一个是使用DbUtils.close()方法。其次,你将可以直接使用close()方法关闭Connection的链接。
小结
本章内容到此结束,由于时间仓库,本文或许有很多不尽人意的地方,希望各位能够理解和体谅。
相关推荐
Apache Commons DBUtils是Java开发中的一个实用工具库,主要用于简化JDBC(Java Database Connectivity)的使用。这个资源包"commons-dbutils-1.6-bin.zip"包含了DBUtils 1.6版本的源代码和相关文档,是理解并使用...
总的来说,分析和学习 "org.apache.commons" 的源码是提升Java开发技能的好方法,它可以帮助你更好地理解和应用这些广泛使用的工具类库,提高编程效率和代码质量。同时,参与开源社区,提交补丁或新功能,也是贡献...
Apache Commons DbUtils是Java开发中一个非常实用的数据库操作工具库,它简化了JDBC的使用,降低了数据库操作的复杂性。DbUtils的核心思想是基于Try-Catch-Finally的异常处理模式,使得数据库操作变得更加安全和简洁...
Apache Commons DBUtils是一个Java库,它为数据库操作提供了一个简单且有效的抽象层,使得开发者能够更轻松地处理数据库连接、查询和其他操作。这个"commons-dbutils-1.7-src.zip"压缩包包含了DBUtils 1.7版本的源...
Apache Commons 是一个由 Apache 软件基金会维护的开源项目集合,它提供了许多实用的 Java 类库,旨在简化常见的编程任务。这些库包含了各种各样的功能,从字符串处理到数学运算,再到数据库连接和文件上传等。以下...
Apache Commons DBUtils是一个Java库,它为数据库操作提供了简单且健壮的工具,极大地简化了JDBC编程。这个组件包和源码的分享是供开发者们学习和研究使用,以提高对数据库操作的理解和实践能力。 DBUtils的核心...
**dbutils** 是一个 Apache Commons 项目,它提供了一个简单且高效的 Java 数据库连接工具集。这个工具包是为了简化数据库操作而设计的,它构建在 JDBC(Java Database Connectivity)之上,为开发人员提供了更方便...
**标题:“扩展Apache Commons的DbUtils”** Apache Commons DbUtils是一个轻量级的Java数据库连接库,它简化了与数据库进行交互的任务,特别是在处理简单的CRUD(创建、读取、更新和删除)操作时。DbUtils是基于...
Commons-dbutils是Apache软件基金会提供的一个轻量级Java数据库工具库,它是对JDBC API的一种简化封装。DbUtils主要功能包括数据库连接池管理、结果集处理以及异常处理等,通过它,开发者可以更高效、更安全地执行...
在`commons-dbutils-1.6-src`中,你可以看到DBUtils的源代码,通过阅读源码,你可以深入理解其内部机制,包括异常处理策略、连接池的使用、结果集的处理流程等。这对于定制自己的数据库访问工具或者学习数据库操作的...
"commons免费下载"这个标题可能指的是Apache ...如果你在项目中遇到与上述功能相关的编程需求,Apache Commons很可能是你的好帮手。在使用时,请根据项目需求选择合适的模块,并参考官方文档以获取详细的使用指南。
`commons-dbutils-1.6.jar`是Apache Commons DBUtils库,它是一个简化数据库操作的Java工具包。DBUtils提供了一种简单的接口来执行SQL查询和处理结果集,使得开发者能更专注于业务逻辑而不是数据库交互的细节。 `...
DbUtils是Apache软件基金会开发的一个开源Java库,它是一个轻量级的数据库操作工具,用于简化Java中的数据库访问。在标题“DbUtils-1.7.zip”中,我们可以看出这是DbUtils的1.7版本的压缩包。这个版本可能包含了...
import org.apache.commons.dbutils.handlers.BeanListHandler; public class DBUtilsExample { public static void main(String[] args) { String url = "jdbc:mysql://localhost:3306/mydatabase"; String ...
10. **commons-dbutils-1.3.jar**:Apache Commons DbUtils是一个简单实用的数据库操作库,基于JDBC,提供了便捷的数据库操作接口,如查询、更新、插入和删除等,同时它简化了异常处理。 这些jar包是JavaWeb项目中...
管理你的财务
10. **Commons-DbUtils** (commons-dbutils-1.6的jar包): Apache Commons DbUtils 是一个简单的JDBC工具包,它简化了基础的数据库操作,如执行SQL查询、处理结果集等,降低了出现数据库操作错误的可能性。...
Apache Commons 是一系列小型实用工具库,它为Java开发者提供了丰富的组件和类库,极大地扩展了标准Java库的功能。这些组件涵盖了各种领域,如数据编码、集合操作、配置管理、网络通信、XML处理、脚本执行等。以下是...
依赖jar包:commons.dbcp-1.4,commons.dbutils-1.3,commons.pool-1.5.4包 插件的使用 一、commons-dbutils-1.3的使用 Apache提供的一个对JDBC进行简单封装的开源工具类库, 它能够简化JDBC应用程序的开发,同时也...
Apache Commons DbUtils是一个小型且实用的Java库,用于简化JDBC编程。DbUtils提供了一套便捷的API,可以处理常见的数据库操作,如执行SQL查询、更新、关闭结果集和连接等。DbUtils的使用可以减少代码量,提高代码...