[JavaWeb]关于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;
[JavaWeb]关于DBUtils中QueryRunner的一些解读(转)的更多相关文章
- [JavaWeb]关于DBUtils中QueryRunner的一些解读.
前言:[本文属于原创分享文章, 转载请注明出处, 谢谢.]前面已经有文章说了DBUtils的一些特性, 这里再来详细说下QueryRunner的一些内部实现, 写的有错误的地方还恳请大家指出. Que ...
- 【转载】关于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"?> < ...
随机推荐
- session------>防表单重复提交
方法一:用js控制表单提交--->但是容易在客户端被篡改代码,还是要加的 方法二:session 先给每一个表带上唯一的标志,再把标志存入session 当session中标志和表上标志都不为空 ...
- Restful and 前后端分离---AutoTest newman--postman
http://www.cnblogs.com/zuoshaowei/p/6192863.html https://www.getpostman.com/docs/newman_intro swagge ...
- Genymotion 模拟器的sd卡的位置
今天用genymotion测试一个例子,发现要用sdcard,虽然可以再DDMS的 File Explore 下看到 sdcard目录,也可以看到/mnt/sdcard 目录,但是往他那里传文件,建目 ...
- 剑指Offer——构建乘积数组
题目描述: 给定一个数组A[0,1,...,n-1],请构建一个数组B[0,1,...,n-1],其中B中的元素B[i]=A[0]*A[1]*...*A[i-1]*A[i+1]*...*A[n-1]. ...
- Storm简介及使用
一.Storm概述 网址:http://storm.apache.org/ Apache Storm是一个免费的开源分布式实时计算系统.Storm可以轻松可靠地处理无限数据流,实现Hadoop对批处理 ...
- 13.Query for Null or Missing Fields-官方文档摘录
1 插入数据 db.inventory.insertMany([ { _id: 1, item: null }, { _id: 2 } ]) 2 查询null值 db.inventory.find({ ...
- Python并行编程(六):线程同步之条件
1.基本概念 条件指的是应用程序状态的改变.其中某些线程在等待某一条件发生,其 他线程会在该条件发生的时候进行通知,一旦条件发生,线程会拿到共享资源的唯一权限. 2.示例代码 from threadi ...
- 浅析Android View(二)
深入理解Android View(一) View的位置參数信息 二.View的绘制过程 View的绘制过程一共分为三个部分: - measure(測量View的大小) - layout(确定View的 ...
- data.table进阶
上一篇讲述了data.table数据分析的一些基本方法,但是最近在用作数据分析时,发现在面对一些复杂场景时,这些基本的用法已经不能满足业务需求了,所以此篇就介绍data.table更进一步的用法. 先 ...
- POJ1185:炮兵阵地(状压dp)
题目:http://poj.org/problem?id=1185 大神的题解: 方法就是用DP[i][r][p]表示第i行状态为r,第i-1行状态是p时的最多个数.而这里p受到r的限制,而第i-2行 ...