JDBC的批次更新

来源:互联网 发布:淘宝天下是做什么的 编辑:程序博客网 时间:2024/06/04 18:45

对于数据库的操作,每一次执行executeUpdate(),其实都会向数据库发送一次SQL,每次发送都等同于通过网络进行了一次信息传送。而网络传送信息实际上必须启动I/O、进行路由等动作,这样进行大量更新,当执行的次数过多时,性能会很低,因此批量更新显得尤为重要!

在使用批量更新之前我们进行大量数据更新是使用如下的代码段:

Statement stmt = conn.createStatement();while( [condition is true] ){    stmt.executeUpdate( [sql] );}

我们可以通过使用addBatch()方法来收集SQL,并使用executeBatch()方法将所有的SQL传送出去,如下是通过Statement 来进行批次更新:

Statement stmt = conn.createStatement();while( <condition is true> ){    stmt.addBatch( <sql> );}stmt.executeBatch();

其中Statement实例中的addBatch()是使用了ArrayList来收集SQL,Mysql驱动程序的Statement的源码如下所示:

    public void addBatch(String sql) throws SQLException {        synchronized(this.checkClosed().getConnectionMutex()) {            if(this.batchedArgs == null) {                this.batchedArgs = new ArrayList();            }            if(sql != null) {                this.batchedArgs.add(sql);            }        }    }

顺带一提,当初找这个源码的时候发现在Jdk中只有一个Statement的接口的声明,并没有具体的源码,由于不同的数据库驱动厂商对接口的实现做了不同的处理,因而Mysql的Statement具体源码的实现在com.mysql.jdbc.StatementImpl。

通过源码可以看出,addBatch()方法会收集所有的SQL,最后串为一句SQL,最终传给数据库,当大量更新产生时,这些SQL语句就会通过一次网络传送给数据库,节省了I/O、网络路由等操作所消耗的时间。

需要注意的是批次更新限制了SQL语句不能是SELECT,否则会抛出异常。

最终在数据库执行时的顺序就是addBatch()的顺序,executeBatch()会返回int[] , 代表每笔SQL造成的数据异动列数。任何的SQL错误都会抛出BatchUpdateException,可以使用该对象的getUpdateCounts()取得int[], 代表先前执行成功的SQL所造成的异动笔数。

上面是一个Statement的例子,如果是使用PreparedStatement进行批次更新,如下是一个范例:

    PreparStatement stmt = conn.preparedStatemnt("insert into table(key, key) values(?, ?)");    while( <condition is true> ){        stmt.setString(1, "..");        stmt.setString(1, "..");        stmt.addBatch(); //收集参数    }    stmt.executeBatch(); //执行送出所有参数

Mysql的PreparedStatement实现类的addBatch()源码如下:

    public void addBatch() throws SQLException {        synchronized(this.checkClosed().getConnectionMutex()) {            if(this.batchedArgs == null) {                this.batchedArgs = new ArrayList();            }            for(int i = 0; i < this.parameterValues.length; ++i) {                this.checkAllParametersSet(this.parameterValues[i], this.parameterStreams[i], i);            }            this.batchedArgs.add(new PreparedStatement.BatchParams(this.parameterValues, this.parameterStreams, this.isStream, this.streamLengths, this.isNull));        }    }

从源码可以看出addBatch()会收集占位字符真正的数值,内部是使用ArrayList来收集占位字符实际的数值。

驱动程序本身是否支持批次更新也要注意,比如Mysql要支持批次更新,必须在JDBC URL上附加rewriteBatchedStatements=true参数才有作用。

0 0
原创粉丝点击