今天分析一下QueryRunner这个DbUtils核心类,它
利用可插拨的策略执行SQL查询来处理ResultSets。QueryRunner类图如下所示:
从类图中我们可以看出它继承AbstractQueryRunner。
QueryRunner构造器有多个重载方法:
public AbstractQueryRunner() {
ds = null;
}
/**
* Constructor to control the use of <code>ParameterMetaData</code>.
*
* @param pmdKnownBroken
* Some drivers don't support
* {@link 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 AbstractQueryRunner(boolean pmdKnownBroken) {
this.pmdKnownBroken = pmdKnownBroken;
ds = null;
}
/**
* Constructor to provide a <code>DataSource</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.
*/
public AbstractQueryRunner(DataSource ds) {
this.ds = ds;
}
/**
* Constructor to provide a <code>DataSource</code> and control 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 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 AbstractQueryRunner(DataSource ds, boolean pmdKnownBroken) {
this.pmdKnownBroken = pmdKnownBroken;
this.ds = ds;
}
构造函数中有两个成员变量:boolean类型的pmdKnownBroken和DataSource类型的ds。
有些情况下,你需要在PreparedStatement中设置空值,这个时候如果你还使用设置具体类型的方法,如setInt(1,null),程序会毫不留情的报出空指针异常,所以你需要做的是使用setNull(index, type)方法来代替你原来的方法。例如
stmt.setNull(1,Types.INTEGER);
第二个参数为java.sql.Types中具体的类型值,你可以通过Types查找到你需要的具体类型。通过这个方法,就可以完成在PreparedStatement设置null值,前提当然是你的数据库字段允许null值。
pmdKnownBroken这个变量,源码的解释是这样的:有些数据库驱动程序不支持ParameterMetaData.getParameterType方法,如果pmdKnownBroken设置为false,在调用fillStatement进行SQL参数填充的时候,如果某个参数值为NULL,我们则会尝试着使用ParameterMetaData.getParameterType方法来获取参数类型,如果有异常抛出,则将pmdKnownBroken值置为 true,以后不再使用。如果pmdKnownBroken设置为true,不进行getParameterType尝试处理。
pmdKnownBroken被定义为volatile类型原因是为了保证这个类的线程安全性。它可以用来确保变量的更新操作通知到其他线程。需要注意的是volatile变量只能保证可见性,在当且仅当满足以下条件的时候才应该使用它:
- 在访问变量时不需要加锁
- 对变量的写入操作不会依赖变量的当前值,或者确保只有当个线程更新变量值
- 该变量不会和其他状态变量一起纳入不变性条件中
显然pmdKnownBroken满足以上使用条件。它只是某个状态标记。
private volatile boolean pmdKnownBroken = false;
/**
* Fill the <code>PreparedStatement</code> replacement parameters wi