JDBC的批次更新

对于数据库的操作,每一次执行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参数才有作用。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值