[JavaWeb]关于DBUtils中QueryRunner的一些解读.
前言:
[本文属于原创分享文章, 转载请注明出处, 谢谢.]
前面已经有文章说了DBUtils的一些特性, 这里再来详细说下QueryRunner的一些内部实现, 写的有错误的地方还恳请大家指出.
QueryRunner类
QueryRunner中提供对sql语句操作的API
它主要有三个方法
query() 用于执行select
update() 用于执行insert/update/delete
batch() 批处理
1,Query语句
先来看下query的两种形式, 我们这里主要讲第一个方法, 因为我们用C3P0来统一管理connection.(QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource()))
query(sql,ResultSetHandler,Object...params);
query(conn,sql,ResultSetHandler,Object...params);
第一种: 不需要params
- //查询所有图书
- public List<Book> selectAllBooks() throws SQLException {
- QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
- return qr.query("select * from books", new BeanListHandler<Book>(Book.class));
- }
第二种: 需要一个参数查询
- //根据id查询指定的书
- public Book selectBookById(String id) throws SQLException {
- QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
- return qr.query("select * from books where id=?", new BeanHandler(Book.class),id);
- }
第三种:需要多个参数查询
- //多条件查询图书信息
- public List<Book> findBookByManyCondition(String id, String category,
- String name, String minprice, String maxprice) throws SQLException {
- StringBuilder sql = new StringBuilder("select * from books where 1=1");
- List list = new ArrayList();
- if(!"".equals(id)){
- sql.append(" and id like ?");
- list.add("%"+id+"%");
- }
- if(!"".equals(category)){
- sql.append(" and category=?");
- list.add(category);
- }
- if(!"".equals(name)){
- sql.append(" and name like ?");
- list.add("%"+name+"%");
- }
- if(!"".equals(minprice)){
- sql.append(" and price > ?");
- list.add(minprice);
- }
- if(!"".equals(maxprice)){
- sql.append(" and price < ?");
- list.add(maxprice);
- }
- QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
- return qr.query(sql.toString(),new BeanListHandler<Book>(Book.class),list.toArray());
- }
那么我们来看下源码的实现:
(1)QueryRunner.java
- //第一种情况,无参数
- public <T> T query(String sql, ResultSetHandler<T> rsh) throws SQLException {
- Connection conn = this.prepareConnection();
- return this.query(conn, true, sql, rsh, (Object[]) null);
- }
- //第二种和第三种使用同一方法: 需要参数
- public <T> T query(String sql, ResultSetHandler<T> rsh, Object... params) throws SQLException {
- Connection conn = this.prepareConnection();
- return this.query(conn, true, sql, rsh, params);
- }
解读: 这里先是获取connection, 利用this.preparaConnection() 获取. 然后调用query()方法去执行查询语句. 接下来看源码是如何获取到当前传输过来的connection以及query()方法的内部实现.
- protected Connection prepareConnection() throws SQLException {
- if (this.getDataSource() == null) {
- throw new SQLException("QueryRunner requires a DataSource to be " +
- "invoked in this way, or a Connection should be passed in");
- }
- return this.getDataSource().getConnection();
- }
这里很简单, 因为我们用的C3P0数据库连接池获取的DataSource, 所以这里直就可以过去到当前的Connection.接下来就看下query()方法的内部实现.
- 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;
- }
解读: 在这里可以看出, 无论是否有传递参数params, 都调用的是同一个query方法, 接着来看this.fillStatement(stmt, params);是如何将参数赋予preparedStatement中的.
- public void fillStatement(PreparedStatement stmt, Object... params) throws SQLException {
- // check the parameter count, if we can
- ParameterMetaData pmd = null;
- if (!pmdKnownBroken) {
- pmd = stmt.getParameterMetaData();
- int stmtCount = pmd.getParameterCount();
- int paramsCount = params == null ? 0 : params.length;
- if (stmtCount != paramsCount) {
- throw new SQLException("Wrong number of parameters: expected "
- + stmtCount + ", was given " + paramsCount);
- }
- }
- // nothing to do here
- if (params == null) {
- return;
- }
- for (int i = 0; i < params.length; i++) {
- if (params[i] != null) {
- stmt.setObject(i + 1, params[i]);
- } else {
- // VARCHAR works with many drivers regardless
- // of the actual column type. Oddly, NULL and
- // OTHER don't work with Oracle's drivers.
- int sqlType = Types.VARCHAR;
- if (!pmdKnownBroken) {
- try {
- sqlType = pmd.getParameterType(i + 1);
- } catch (SQLException e) {
- pmdKnownBroken = true;
- }
- }
- stmt.setNull(i + 1, sqlType);
- }
- }
- }
这个方法就是核心所在.
第一种情况: 当params为null的时候, 直接return然后执行sql语句.
第二种第三种情况: 当params不为null时, 循环遍历传入的params, 然后将params赋值到preparedStatement中, 然后填充占位符进行sql查询. 这里我们也来回顾下直接使用preparedStatement来进行查询的方式:
- @Test
- public void update(){
- Connection conn = null;
- PreparedStatement st = null;
- ResultSet rs = null;
- try{
- conn = JdbcUtils.getConnection();
- String sql = "update users set name=?,email=? where id=?";
- st = conn.prepareStatement(sql);
- st.setString(1, "gacl");
- st.setString(2, "gacl@sina.com");
- st.setInt(3, 2);
- int num = st.executeUpdate();
- if(num>0){
- System.out.println("更新成功!!");
- }
- }catch (Exception e) {
- e.printStackTrace();
- }finally{
- JdbcUtils.release(conn, st, rs);
- }
- }
- @Test
- public void find(){
- Connection conn = null;
- PreparedStatement st = null;
- ResultSet rs = null;
- try{
- conn = JdbcUtils.getConnection();
- String sql = "select * from users where id=?";
- st = conn.prepareStatement(sql);
- st.setInt(1, 1);
- rs = st.executeQuery();
- if(rs.next()){
- System.out.println(rs.getString("name"));
- }
- }catch (Exception e) {
- }finally{
- JdbcUtils.release(conn, st, rs);
- }
- }
2, Update语句
查看update语句:
- //修改图书
- public void updateBook(Book book) throws SQLException {
- QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
- qr.update(
- "UPDATE books SET NAME=? ,price=?,bnum=?,category=?,description=? WHERE id=?",
- book.getName(), book.getPrice(), book.getBnum(),
- book.getCategory(), book.getDescription(), book.getId())
- }
接着是QueryRunner.java中的update 方法:
- public int update(String sql, Object... params) throws SQLException {
- Connection conn = this.prepareConnection();
- return this.update(conn, true, sql, params);
- }
- private int update(Connection conn, boolean closeConn, String sql, 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");
- }
- PreparedStatement stmt = null;
- int rows = 0;
- try {
- stmt = this.prepareStatement(conn, sql);
- this.fillStatement(stmt, params);
- rows = stmt.executeUpdate();
- } catch (SQLException e) {
- this.rethrow(e, sql, params);
- } finally {
- close(stmt);
- if (closeConn) {
- close(conn);
- }
- }
- return rows;
- }
到了参数赋值的时候又调用了上面的fillStatement方法, 这里就不再阐述了.
3, Batch语句
这里直接看batch方法的实例, 然后结合源码的实现.
- //批量删除
- public void delBooks(String[] ids) throws SQLException {
- QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
- Object[][] params = new Object[ids.length][];//高维确定执行sql语句的次数,低维是给?赋值
- for (int i = 0; i < params.length; i++) {
- params[i] = new Object[]{ids[i]};//给“?”赋值
- }
- qr.batch("delete from books where id=?", params);
- }
然后看QueryRunner中的batch()方法:
- public int[] batch(String sql, Object[][] params) throws SQLException {
- Connection conn = this.prepareConnection();
- return this.batch(conn, true, sql, params);
- }
- private int[] batch(Connection conn, boolean closeConn, String sql, 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 (params == null) {
- if (closeConn) {
- close(conn);
- }
- throw new SQLException("Null parameters. If parameters aren't need, pass an empty array.");
- }
- PreparedStatement stmt = null;
- int[] rows = null;
- try {
- stmt = this.prepareStatement(conn, sql);
- for (int i = 0; i < params.length; i++) {
- this.fillStatement(stmt, params[i]);
- stmt.addBatch();
- }
- rows = stmt.executeBatch();
- } catch (SQLException e) {
- this.rethrow(e, sql, (Object[])params);
- } finally {
- close(stmt);
- if (closeConn) {
- close(conn);
- }
- }
- return rows;
- }
解读: 因为params是一个二维数组, 所以往preparedStatement中赋值的时候使用了for循环, 然后通过preparedstatement.addBatch() 进行批量添加, 然后执行executeBatch()进行操作.
- /**
- * Adds a set of parameters to this <code>PreparedStatement</code>
- * object's batch of commands.
- *
- * @exception SQLException if a database access error occurs or
- * this method is called on a closed <code>PreparedStatement</code>
- * @see Statement#addBatch
- * @since 1.2
- */
- void addBatch() throws SQLException;
一看时间这么晚了, QueryRunner暂时就这么多了, 关于QueryRunner的用法自己挖掘的还不够透彻, 写在这里当做记录和交流. 2016/05/24.
[JavaWeb]关于DBUtils中QueryRunner的一些解读.的更多相关文章
- [JavaWeb]关于DBUtils中QueryRunner的一些解读(转)
QueryRunner类 QueryRunner中提供对sql语句操作的API它主要有三个方法 query() 用于执行select update() 用于执行insert/update/delete ...
- 【转载】关于DBUtils中QueryRunner的一些解读
前面已经有文章说了DBUtils的一些特性, 这里再来详细说下QueryRunner的一些内部实现, 写的有错误的地方还恳请大家指出. QueryRunner类 QueryRunner中提供对sql语 ...
- 关于dbutils中QueryRunner看批量删除语句batch
//批量删除 public void delBooks(String[] ids) throws SQLException { QueryRunner qr = new QueryRunner(C3P ...
- 【JavaWeb】DbUtils入门之QueryRunner
DbUtils简介 根据官网的介绍,DbUtils是一种 JDBC Utility Component (翻译过来大概就是:JDBC实用部件),故名思意,和数据库操作有关 官网上的简介也称之为 JDB ...
- JavaWeb之DBUtils
一.什么是DBUtils及作用 DBUtils是apache公司写的.DBUtils是java编程中的数据库操作实用工具,小巧简单实用. DBUtils封装了对JDBC的操作,简化了JDBC操作.可以 ...
- JavaWeb之DButils整理
一.DBUtils介绍 apache 什么是dbutils,它的作用 DBUtils是java编程中的数据库操作实用工具,小巧简单实用. 用前导包!!!DBUtils包!!! 二.DBUtils的三 ...
- java—在dbutils中处理事务与不确定条件的查询(46)
在dbutils中处理事务 事务是指用户的一次操作.这一次操作有可能是一个表,也有可能是多个表,也有可能是对一个表的多次操作. 只要是: 1:对数据数据库进行多次操作. 2:多个表,还是 ...
- BiLSTM-CRF模型中CRF层的解读
转自: https://createmomo.github.io/ BiLSTM-CRF模型中CRF层的解读: 文章链接: 标题:CRF Layer on the Top of BiLSTM - 1 ...
- 在jdbc基础上进阶一小步的C3p0 连接池(DBCP 不能读xml配置文件,已淘汰) 和DBUtils 中两个主要类QueryRunner和ResultSetHandler的使用
首先看C3p0这个连接池,最大优势可以自动读取默认的配置文件 <?xml version="1.0" encoding="UTF-8"?> < ...
随机推荐
- java时区问题的一个坑
事情是这样的,前台传过去一个日期字符串,就像2016/12/15 00:00,2016/12/15 23:59类似的格式,但每次从日志平台查日志查询的时间范围都不对,而是提前了一天. 原因是在java ...
- MySQL入门手册
本文内容摘自MySQL5.6官方文档,主要选取了在实践过程中所用到的部分文字解释,力求只摘录重点,快速学会使用MySQL,本文所贴代码地方就是我亲自练习过的代码,凡本文没有练习过的代码都没有贴在此处, ...
- Postman-CI集成Jenkins
Postman-简单使用 Postman-进阶使用 Postman-CI集成Jenkins Newman 官方说明:Postman's command-line companion lets you ...
- BZOJ2683 简单题(CDQ分治)
传送门 之前听别人说CDQ分治不难学,今天才知道果真如此.之前一直为自己想不到CDQ的方法二很不爽,今天终于是想出来了一道了,太弱-- cdq分治主要就是把整段区间分成两半,然后用左区间的值去更新右区 ...
- Jetty源码分析(一)
一.目的 1.了解jetty组成架构: 2.学习jetty启动过程: 3.学习请求访问过程: 4.学习jetty内各模块作用,学习各模块内部代码: 二.jetty版本 本文所学习的jetty版本为:9 ...
- 解决hadoop启动后datanode无法启动问题
hadoop部署完成后datanode无法启动问题解决 1.检查是否有遗留的hadoop进程还在运行,如果有的话,先stop-all.sh或kill杀掉: 2.在master节点上,删除/tmp/ha ...
- android 编译代码注意事项
1 安装openjdk1.7 sudo add-apt-repository ppa:openjdk-r/ppa sudo apt-apt update sudo apt-get install op ...
- IO-02. 整数四则运算(10)
本题要求编写程序,计算2个正整数的和.差.积.商并输出.题目保证输入和输出全部在整型范围内. 输入格式: 输入在一行中给出2个正整数A和B. 输出格式: 在4行中按照格式“A 运算符 B = 结果”顺 ...
- LINUX下常用SHELL指令
Linux Shell常用shell命令 一.文件.目录操作命令 1.ls命令 功能:显示文件和目录的信息 ls 以默认方式显示当前目录文件列表 ls -a 显示所有文件包括隐藏文件 ls -l 显示 ...
- JavaScript 学习笔记(一)
1.javascript中,值包括原始值和对象,原始值包括布尔值.数字.字符串.null和undefined,其他的值为对象. 原始值的特点:(1)按值进行比较:3===3> true; 'ab ...