/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org.
apache.
commons.
dbutils;
import
java.
sql.
Connection;
import
java.
sql.
PreparedStatement;
import
java.
sql.
ResultSet;
import
java.
sql.
SQLException;
import
javax.
sql.
DataSource;
/**
* Executes SQL queries with pluggable strategies for handling
* <code>ResultSet</code>s. This class is thread safe.
* 執行SQL查詢語句,使用策略模式對結果進行處理。此類是線程安全的
* 這個類關聯到一個重要的接口:ResultSetHandler
*/
public
class
QueryRunner
extends
AbstractQueryRunner {
/**
* Constructor for QueryRunner.
*/
public
QueryRunner() {
super();
}
/**
* Constructor for QueryRunner that controls the use of <code>ParameterMetaData</code>.
*
*
@param
pmdKnownBroken Some drivers don't support {
@link
java.sql.ParameterMetaData#getParameterType(int) };
* if <code>pmdKnownBroken</code> is set to true, we won't even try it; if false, we'll try it,
* and if it breaks, we'll remember not to use it again.
*/
public
QueryRunner(
boolean
pmdKnownBroken) {
super(
pmdKnownBroken);
}
/**
* Constructor for QueryRunner that takes a <code>DataSource</code> to use.
*
* Methods that do not take a <code>Connection</code> parameter will retrieve connections from this
* <code>DataSource</code>.
*
*
@param
ds The <code>DataSource</code> to retrieve connections from.
*/
public
QueryRunner(
DataSource
ds) {
super(
ds);
}
/**
* Constructor for QueryRunner that takes a <code>DataSource</code> and controls the use of <code>ParameterMetaData</code>.
* Methods that do not take a <code>Connection</code> parameter will retrieve connections from this
* <code>DataSource</code>.
*
*
@param
ds The <code>DataSource</code> to retrieve connections from.
*
@param
pmdKnownBroken Some drivers don't support {
@link
java.sql.ParameterMetaData#getParameterType(int) };
* if <code>pmdKnownBroken</code> is set to true, we won't even try it; if false, we'll try it,
* and if it breaks, we'll remember not to use it again.
*/
public
QueryRunner(
DataSource
ds,
boolean
pmdKnownBroken) {
super(
ds,
pmdKnownBroken);
}
/**
* Execute a batch of SQL INSERT, UPDATE, or DELETE queries.
* 批量處理INSERT、UPDATE、DELETE
*
@param
conn The Connection to use to run the query. The caller is
* responsible for closing this Connection.
*
@param
sql The SQL to execute.
*
@param
params An array of query replacement parameters. Each row in
* this array is one set of batch replacement values.
*
@return
The number of rows updated per statement.
*
@throws
SQLException if a database access error occurs
*/
public
int[]
batch(
Connection
conn,
String
sql,
Object[][]
params)
throws
SQLException {
return
this.
batch(
conn,
false,
sql,
params);
}
/**
* Execute a batch of SQL INSERT, UPDATE, or DELETE queries. The
* <code>Connection</code> is retrieved from the <code>DataSource</code>
* set in the constructor. This <code>Connection</code> must be in
* auto-commit mode or the update will not be saved.
*
*
@param
sql The SQL to execute.
*
@param
params An array of query replacement parameters. Each row in
* this array is one set of batch replacement values.
*
@return
The number of rows updated per statement.
*
@throws
SQLException if a database access error occurs
*/
public
int[]
batch(
String
sql,
Object[][]
params)
throws
SQLException {
Connection
conn
=
this.
prepareConnection();
return
this.
batch(
conn,
true,
sql,
params);
}
/**
* Calls update after checking the parameters to ensure nothing is null.
*
@param
conn The connection to use for the batch call.
*
@param
closeConn True if the connection should be closed, false otherwise.
*
@param
sql The SQL statement to execute.
*
@param
params An array of query replacement parameters. Each row in
* this array is one set of batch replacement values.
*
@return
The number of rows updated in the batch.
*
@throws
SQLException If there are database or parameter errors.
*/
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;
}
/**
* Execute an SQL SELECT query with a single replacement parameter. The
* caller is responsible for closing the connection.
*
@param
<T> The type of object that the handler returns
*
@param
conn The connection to execute the query in.
*
@param
sql The query to execute.
*
@param
param The replacement parameter.
*
@param
rsh The handler that converts the results into an object.
*
@return
The object returned by the handler.
*
@throws
SQLException if a database access error occurs
*
@deprecated
Use {
@link
#query(Connection, String, ResultSetHandler, Object...)}
*/
@
Deprecated
public
<
T
>
T
query(
Connection
conn,
String
sql,
Object
param,
ResultSetHandler
<
T
>
rsh)
throws
SQLException {
return
this.
<
T
>
query(
conn,
false,
sql,
rsh,
new
Object[]{
param});
}
/**
* Execute an SQL SELECT query with replacement parameters. The
* caller is responsible for closing the connection.
*
@param
<T> The type of object that the handler returns
*
@param
conn The connection to execute the query in.
*
@param
sql The query to execute.
*
@param
params The replacement parameters.
*
@param
rsh The handler that converts the results into an object.
*
@return
The object returned by the handler.
*
@throws
SQLException if a database access error occurs
*
@deprecated
Use {
@link
#query(Connection,String,ResultSetHandler,Object...)} instead
*/
@
Deprecated
public
<
T
>
T
query(
Connection
conn,
String
sql,
Object[]
params,
ResultSetHandler
<
T
>
rsh)
throws
SQLException {
return
this.
<
T
>
query(
conn,
false,
sql,
rsh,
params);
}
/**
* Execute an SQL SELECT query with replacement parameters. The
* caller is responsible for closing the connection.
*
@param
<T> The type of object that the handler returns
*
@param
conn The connection to execute the query in.
*
@param
sql The query to execute.
*
@param
rsh The handler that converts the results into an object.
*
@param
params The replacement parameters.
*
@return
The object returned by the handler.
*
@throws
SQLException if a database access error occurs
*/
public
<
T
>
T
query(
Connection
conn,
String
sql,
ResultSetHandler
<
T
>
rsh,
Object...
params)
throws
SQLException {
return
this.
<
T
>
query(
conn,
false,
sql,
rsh,
params);
}
/**
* Execute an SQL SELECT query without any replacement parameters. The
* caller is responsible for closing the connection.
*
@param
<T> The type of object that the handler returns
*
@param
conn The connection to execute the query in.
*
@param
sql The query to execute.
*
@param
rsh The handler that converts the results into an object.
*
@return
The object returned by the handler.
*
@throws
SQLException if a database access error occurs
*/
public
<
T
>
T
query(
Connection
conn,
String
sql,
ResultSetHandler
<
T
>
rsh)
throws
SQLException {
return
this.
<
T
>
query(
conn,
false,
sql,
rsh, (
Object[])
null);
}
/**
* Executes the given SELECT SQL with a single replacement parameter.
* The <code>Connection</code> is retrieved from the
* <code>DataSource</code> set in the constructor.
*
@param
<T> The type of object that the handler returns
*
@param
sql The SQL statement to execute.
*
@param
param The replacement parameter.
*
@param
rsh The handler used to create the result object from
* the <code>ResultSet</code>.
*
*
@return
An object generated by the handler.
*
@throws
SQLException if a database access error occurs
*
@deprecated
Use {
@link
#query(String, ResultSetHandler, Object...)}
*/
@
Deprecated
public
<
T
>
T
query(
String
sql,
Object
param,
ResultSetHandler
<
T
>
rsh)
throws
SQLException {
Connection
conn
=
this.
prepareConnection();
return
this.
<
T
>
query(
conn,
true,
sql,
rsh,
new
Object[]{
param});
}
/**
* Executes the given SELECT SQL query and returns a result object.
* The <code>Connection</code> is retrieved from the
* <code>DataSource</code> set in the constructor.
* 這個方法使用的是數組參數,後來改爲使用了可變參數
*
@param
<T> The type of object that the handler returns
*
@param
sql The SQL statement to execute.
*
@param
params Initialize the PreparedStatement's IN parameters with
* this array.
*
*
@param
rsh The handler used to create the result object from
* the <code>ResultSet</code>.
*
*
@return
An object generated by the handler.
*
@throws
SQLException if a database access error occurs
*
@deprecated
Use {
@link
#query(String, ResultSetHandler, Object...)}
*/
@
Deprecated
public
<
T
>
T
query(
String
sql,
Object[]
params,
ResultSetHandler
<
T
>
rsh)
throws
SQLException {
Connection
conn
=
this.
prepareConnection();
return
this.
<
T
>
query(
conn,
true,
sql,
rsh,
params);
}
/**
* Executes the given SELECT SQL query and returns a result object.
* 執行給定的查詢語句,返回一個結果對象
* The <code>Connection</code> is retrieved from the
* <code>DataSource</code> set in the constructor.
* 在方法內部:從數據源中獲得鏈接
*
@param
<T> The type of object that the handler returns
*
@param
sql The SQL statement to execute.
*
@param
rsh The handler used to create the result object from
* the <code>ResultSet</code>.
* 此handler是用來對ResultSet進行處理的,使用了策略模式
*
@param
params Initialize the PreparedStatement's IN parameters with
* this array.
*
@return
An object generated by the handler.
*
@throws
SQLException if a database access error occurs
*/
public
<
T
>
T
query(
String
sql,
ResultSetHandler
<
T
>
rsh,
Object...
params)
throws
SQLException {
//獲得數據庫連接。繼承過來的方法。
Connection
conn
=
this.
prepareConnection();
return
this.
<
T
>
query(
conn,
true,
sql,
rsh,
params);
}
/**
* Executes the given SELECT SQL without any replacement parameters.
* 執行查詢語句,這個查詢語句沒有使用到參數,例如:select * from t_user
* The <code>Connection</code> is retrieved from the
* <code>DataSource</code> set in the constructor.
*
@param
<T> The type of object that the handler returns
*
@param
sql The SQL statement to execute.
*
@param
rsh The handler used to create the result object from
* the <code>ResultSet</code>.
*
*
@return
An object generated by the handler.
*
@throws
SQLException if a database access error occurs
*/
public
<
T
>
T
query(
String
sql,
ResultSetHandler
<
T
>
rsh)
throws
SQLException {
//獲得數據庫連接。繼承過來的方法。
Connection
conn
=
this.
prepareConnection();
return
this.
<
T
>
query(
conn,
true,
sql,
rsh, (
Object[])
null);
}
/**
* Calls query after checking the parameters to ensure nothing is null.
*
@param
conn The connection to use for the query call.
*
@param
closeConn True if the connection should be closed, false otherwise.
*
@param
sql The SQL statement to execute.
*
@param
params An array of query replacement parameters. Each row in
* this array is one set of batch replacement values.
*
@return
The results of the query.
*
@throws
SQLException If there are database or parameter errors.
*/
private
<
T
>
T
query(
Connection
conn,
boolean
closeConn,
String
sql,
ResultSetHandler
<
T
>
rsh,
Object...
params)
throws
SQLException {
//數據庫連接爲null,那麼報錯
if (
conn
==
null) {
throw
new
SQLException(
"Null connection");
}
//SQL語句爲null,報錯。沒語句,執行什麼呢?
if (
sql
==
null) {
if (
closeConn) {
//SQL語句都爲空,要數據庫連接幹什麼
close(
conn);
}
throw
new
SQLException(
"Null SQL statement");
}
//結果集爲null,報錯。
if (
rsh
==
null) {
if (
closeConn) {
close(
conn);
}
throw
new
SQLException(
"Null ResultSetHandler");
}
//定義一個PreparedStatement類型變量
PreparedStatement
stmt
=
null;
//定義一個ResultSet類型變量
ResultSet
rs
=
null;
T
result
=
null;
//泛型。用戶最終要的結果
try {
//準備PreparedStatement對象,此方法是從父類繼承過來的
stmt
=
this.
prepareStatement(
conn,
sql);
//填充?佔位符,此方法是從父類繼承過來的
this.
fillStatement(
stmt,
params);
//執行SQL語句。包裝結果集,此方法是從父類繼承過來的,其實wrap只是把傳進去的RS又return了
rs
=
this.
wrap(
stmt.
executeQuery());
/**
* 對結果集進行處理。策略模式。對於結果進行如何處理,交由用戶處理。dbutils已經實現了常用的
* ResultSetHandler。用戶可以實現自己的ResultSetHandler,只要實現接口
* ResultSetHandler即可
*/
result
=
rsh.
handle(
rs);
}
catch (
SQLException
e) {
this.
rethrow(
e,
sql,
params);
}
finally {
//釋放資源
try {
close(
rs);
}
finally {
close(
stmt);
if (
closeConn) {
close(
conn);
}
}
}
//返回用戶要的結果。此結果就是ResultSetHandler中的handle方法返回的結果
return
result;
}
/**
* Execute an SQL INSERT, UPDATE, or DELETE query without replacement
* parameters.
* 這裏執行的是不帶參數的SQL語句
*
@param
conn The connection to use to run the query.
*
@param
sql The SQL to execute.
*
@return
The number of rows updated.
*
@throws
SQLException if a database access error occurs
*/
public
int
update(
Connection
conn,
String
sql)
throws
SQLException {
return
this.
update(
conn,
false,
sql, (
Object[])
null);
}
/**
* Execute an SQL INSERT, UPDATE, or DELETE query with a single replacement
* parameter.
*
*
@param
conn The connection to use to run the query.
*
@param
sql The SQL to execute.
*
@param
param The replacement parameter.
*
@return
The number of rows updated.
*
@throws
SQLException if a database access error occurs
*/
public
int
update(
Connection
conn,
String
sql,
Object
param)
throws
SQLException {
return
this.
update(
conn,
false,
sql,
new
Object[]{
param});
}
/**
* Execute an SQL INSERT, UPDATE, or DELETE query.
*
*
@param
conn The connection to use to run the query.
*
@param
sql The SQL to execute.
*
@param
params The query replacement parameters.
*
@return
The number of rows updated.
*
@throws
SQLException if a database access error occurs
*/
public
int
update(
Connection
conn,
String
sql,
Object...
params)
throws
SQLException {
return
update(
conn,
false,
sql,
params);
}
/**
* Executes the given INSERT, UPDATE, or DELETE SQL statement without
* any replacement parameters. The <code>Connection</code> is retrieved
* from the <code>DataSource</code> set in the constructor. This
* <code>Connection</code> must be in auto-commit mode or the update will
* not be saved.
* 執行給定的INSERT,UPDATE,或DELETE語句,語句中沒有可替代的參數。Connection從數據源中獲得。
* 這個連接必須爲自動提交模式。,否則更新操做不會被保存。
*
@param
sql The SQL statement to execute.
*
@throws
SQLException if a database access error occurs
*
@return
The number of rows updated.
*/
public
int
update(
String
sql)
throws
SQLException {
Connection
conn
=
this.
prepareConnection();
//執行,因爲沒使用到參數,所以給個null
return
this.
update(
conn,
true,
sql, (
Object[])
null);
}
/**
* Executes the given INSERT, UPDATE, or DELETE SQL statement with
* a single replacement parameter. The <code>Connection</code> is
* retrieved from the <code>DataSource</code> set in the constructor.
* This <code>Connection</code> must be in auto-commit mode or the
* update will not be saved.
* 執行給定的INSERT,UPDATE,或DELETE語句,語句中有且僅有一個可替代的參數。Connection從數據源中獲得。
* 這個連接必須爲自動提交模式。,否則更新操做不會被保存。
*
@param
sql The SQL statement to execute.
*
@param
param The replacement parameter.
*
@throws
SQLException if a database access error occurs
*
@return
The number of rows updated.
*/
public
int
update(
String
sql,
Object
param)
throws
SQLException {
Connection
conn
=
this.
prepareConnection();
return
this.
update(
conn,
true,
sql,
new
Object[]{
param});
}
/**
* Executes the given INSERT, UPDATE, or DELETE SQL statement. The
* <code>Connection</code> is retrieved from the <code>DataSource</code>
* set in the constructor. This <code>Connection</code> must be in
* auto-commit mode or the update will not be saved.
* 執行給定的INSERT,UPDATE,或DELETE語句,語句中有多個可替代的參數。Connection從數據源中獲得。
* 這個連接必須爲自動提交模式。,否則更新操做不會被保存。
*
@param
sql The SQL statement to execute.
*
@param
params Initializes the PreparedStatement's IN (i.e. '?')
* parameters.
*
@throws
SQLException if a database access error occurs
*
@return
The number of rows updated.
*/
public
int
update(
String
sql,
Object...
params)
throws
SQLException {
Connection
conn
=
this.
prepareConnection();
return
this.
update(
conn,
true,
sql,
params);
}
/**
* Calls update after checking the parameters to ensure nothing is null.
* 在調用update操做前,檢查一下參數,確保沒有爲null的
*
@param
conn The connection to use for the update call.
*
@param
closeConn True if the connection should be closed, false otherwise.
*
@param
sql The SQL statement to execute.
*
@param
params An array of update replacement parameters. Each row in
* this array is one set of update replacement values.
*
@return
The number of rows updated.
*
@throws
SQLException If there are database or parameter errors.
*/
private
int
update(
Connection
conn,
boolean
closeConn,
String
sql,
Object...
params)
throws
SQLException {
//鏈接都沒,怎麼操做,報錯得了
if (
conn
==
null) {
throw
new
SQLException(
"Null connection");
}
//SQL都沒,怎麼操做,報錯得了。closeConn爲true,就關閉鏈接
if (
sql
==
null) {
if (
closeConn) {
//這裏的close是從父類繼承過來的
close(
conn);
}
throw
new
SQLException(
"Null SQL statement");
}
//定義一個PreparedStatement類型變量
PreparedStatement
stmt
=
null;
//這裏記錄的是受影響的函數。如update了幾行,insert了幾行,delete了幾行
int
rows
=
0;
try {
//獲得prepareStatement變量,此方法是從父類繼承過來的
stmt
=
this.
prepareStatement(
conn,
sql);
//爲prepareStatement中的參數賦值
this.
fillStatement(
stmt,
params);
//執行SQL,返回受影響行數
rows
=
stmt.
executeUpdate();
}
catch (
SQLException
e) {
this.
rethrow(
e,
sql,
params);
}
finally {
//釋放資源
close(
stmt);
if (
closeConn) {
close(
conn);
}
}
//返回結果
return
rows;
}
}