DbUtils源码分析-AbstractQueryRunner

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;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值