1.构造函数
public AbstractQueryRunner();
//pmdKnownBroken用于fillStatement检查参数个数
public AbstractQueryRunner(boolean pmdKnownBroken);
//指定DataSource后续无需指定Connection
public AbstractQueryRunner(DataSource ds);
public AbstractQueryRunner(DataSource ds, boolean pmdKnownBroken);
public AbstractQueryRunner(DataSource ds, boolean pmdKnownBroken, StatementConfiguration stmtConfig);
//StatementConfiguration用于设置ResultSet获取的结果处理,比如ResultSet获取的行数,查询超时时间等,可以在Debug下查看ResultSet的rowData查看结果
public AbstractQueryRunner(DataSource ds, StatementConfiguration stmtConfig);
public AbstractQueryRunner(StatementConfiguration stmtConfig);
2.fillStatement相关函数
public void fillStatement(PreparedStatement stmt, Object... params) throws SQLException {
//检查可变参数和SQL中可替换参数个数是否相等
ParameterMetaData pmd = null;
if (!pmdKnownBroken) {
try {
//有些数据库驱动不支持该方法
pmd = stmt.getParameterMetaData();
if (pmd == null) {
pmdKnownBroken = true;
} else {
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);
}
}
} catch (SQLFeatureNotSupportedException ex) {
pmdKnownBroken = true;
}
}
//可变参数为空没必要set参数了,直接返回
if (params == null) {
return;
}
//CallableStatement 用于执行存储过程,继承至PreparedStatement
CallableStatement call = null;
if (stmt instanceof CallableStatement) {
call = (CallableStatement) stmt;
}
for (int i = 0; i < params.length; i++) {
if (params[i] != null) {
if (call != null && params[i] instanceof OutParameter) {
//所有OutParameter都需要进行注册,相当于在SQL中set @p_out = 'value'
((OutParameter)params[i]).register(call, i + 1);
} else {
//普通SQL,参数只需要set相应的值,底层调用instanceof判断参数类型
stmt.setObject(i + 1, params[i]);
}
} else {
//默认使用varchar处理空值
int sqlType = Types.VARCHAR;
if (!pmdKnownBroken) {
// TODO see DBUTILS-117: does it make sense to catch SQLEx here?
try {
//尝试从params中获取类型
sqlType = pmd.getParameterType(i + 1);
} catch (SQLException e) {
pmdKnownBroken = true;
}
}
//设置为空值
stmt.setNull(i + 1, sqlType);
}
}
}
//一般不使用该方法,该方法需要自己取获取Bean的PropertyDescriptor
public void fillStatementWithBean(PreparedStatement stmt, Object bean, PropertyDescriptor[] properties) throws SQLException {
Object[] params = new Object[properties.length];
for (int i = 0; i < properties.length; i++) {
PropertyDescriptor property = properties[i];
Object value = null;
//获取get方法
Method method = property.getReadMethod();
//一般需要提供get/set方法,否则报错
if (method == null) {
throw new RuntimeException("No read method for bean property "
+ bean.getClass() + " " + property.getName());
}
try {
//get方法一般是无参函数,new Object[0]可以省略?
value = method.invoke(bean, new Object[0]);
} catch (InvocationTargetException e) {
throw new RuntimeException("Couldn't invoke method: " + method,
e);
} catch (IllegalArgumentException e) {
//参数异常
throw new RuntimeException(
"Couldn't invoke method with 0 arguments: " + method, e);
} catch (IllegalAccessException e) {
//访问异常,比如是get方法是protected/private
throw new RuntimeException("Couldn't invoke method: " + method, e);
}
params[i] = value;
}
//通过获取的值填充参数
fillStatement(stmt, params);
}
public void fillStatementWithBean(PreparedStatement stmt, Object bean, String... propertyNames) throws SQLException {
PropertyDescriptor[] descriptors;
try {
//获取bean所有的属性描述器
descriptors = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();
} catch (IntrospectionException e) {
throw new RuntimeException("Couldn't introspect bean "
+ bean.getClass().toString(), e);
}
//按参数顺序组合起来
PropertyDescriptor[] sorted = new PropertyDescriptor[propertyNames.length];
for (int i = 0; i < propertyNames.length; i++) {
String propertyName = propertyNames[i];
if (propertyName == null) {
throw new NullPointerException("propertyName can't be null: " + i);
}
boolean found = false;
for (int j = 0; j < descriptors.length; j++) {
PropertyDescriptor descriptor = descriptors[j];
if (propertyName.equals(descriptor.getName())) {
sorted[i] = descriptor;
found = true;
break;
}
}
if (!found) {
throw new RuntimeException("Couldn't find bean property: "
+ bean.getClass() + " " + propertyName);
}
}
//调用上一个方法
fillStatementWithBean(stmt, bean, sorted);
}
3.prepareStatement相关
protected PreparedStatement prepareStatement(Connection conn, String sql) throws SQLException {
PreparedStatement ps = conn.prepareStatement(sql);
try {
//构造函数指定的StatementConfiguration在这里使用到
configureStatement(ps);
} catch (SQLException e) {
ps.close();
throw e;
}
return ps;
}
protected PreparedStatement prepareStatement(Connection conn, String sql, int returnedKeys)
throws SQLException {
//returnedKeys用于指示是否返回主键,在QueryRunner#insertBatch中使用到Statement.RETURN_GENERATED_KEYS
PreparedStatement ps = conn.prepareStatement(sql, returnedKeys);
try {
configureStatement(ps);
} catch (SQLException e) {
ps.close();
throw e;
}
return ps;
}
4.close相关函数
//简单的调用DbUtils的关闭资源的函数
protected void close(Connection conn) throws SQLException {
DbUtils.close(conn);
}
protected void close(Statement stmt) throws SQLException {
DbUtils.close(stmt);
}
protected void close(ResultSet rs) throws SQLException {
DbUtils.close(rs);
}
5.其他相关函数
private void configureStatement(Statement stmt) throws SQLException {
if (stmtConfig != null) {
/*从数据库读取数据的方向?ResultSet.FETCH_FORWARD/ResultSet.FETCH_REVERSE/ResultSet.FETCH_UNKNOWN
感觉没区别*/
if (stmtConfig.isFetchDirectionSet()) {
stmt.setFetchDirection(stmtConfig.getFetchDirection());
}
/*fetchSize The number of rows that should be fetched from the database when more rows are needed.
当需要要更多行时从数据库获取的行数?hibernate的缓存吗《手动滑稽》?不会使用这个*/
if (stmtConfig.isFetchSizeSet()) {
stmt.setFetchSize(stmtConfig.getFetchSize());
}
//每列/字段返回最大的字节数
if (stmtConfig.isMaxFieldSizeSet()) {
stmt.setMaxFieldSize(stmtConfig.getMaxFieldSize());
}
//这个比较好理解,从数据库中读取的行数,MySql中limit若大于这个值,查询以maxRows为准,小于则以limit为准
if (stmtConfig.isMaxRowsSet()) {
stmt.setMaxRows(stmtConfig.getMaxRows());
}
//设置查询超时限制
if (stmtConfig.isQueryTimeoutSet()) {
stmt.setQueryTimeout(stmtConfig.getQueryTimeout());
}
}
}
public DataSource getDataSource() {
return this.ds;
}
public boolean isPmdKnownBroken() {
return pmdKnownBroken;
}
//ResultSet修饰
protected ResultSet wrap(ResultSet rs) {
return rs;
}
源码中给的示例:
QueryRunner run = new QueryRunner() {
protected ResultSet wrap(ResultSet rs) {
return StringTrimmedResultSet.wrap(rs);
}
};
//异常处理函数,重新包装详细信息后再向上抛出
protected void rethrow(SQLException cause, String sql, Object... params)
throws SQLException {
String causeMessage = cause.getMessage();
if (causeMessage == null) {
causeMessage = "";
}
StringBuffer msg = new StringBuffer(causeMessage);
msg.append(" Query: ");
msg.append(sql);
msg.append(" Parameters: ");
if (params == null) {
msg.append("[]");
} else {
msg.append(Arrays.deepToString(params));
}
SQLException e = new SQLException(msg.toString(), cause.getSQLState(),
cause.getErrorCode());
e.setNextException(cause);
throw e;
}