iBatis批处理

本文重点:

1.  在执行批处理时,方法update和executeBatch的返回值(影响的记录数)不可靠。

2.  批处理必须在显式的事务中进行,并且关闭auto commit。

3.  Batch大小。

 

一.JDBC批处理

和CRUD一样,iBatis通过JDBC支持,封装实现了自己的批处理。下面是一段使用JDBC进行批处理的代码:

Connection conn = ...;

conn.setAutoCommit(false);

 

PreparedStatement ps = conn.prepareStatement("insert into tb (id) values (?)");

for (int i = 0; i < 1000; i++) {

    ps.setInt(1, i);

    ps.addBatch();

}

ps.executeBatch();

conn.commit();

 

ps.close(); // Move this line into a finally block.

conn.close();

 

JDBC 3.0规范提到, JDBC驱动会在调用PreparedStatement#executeBatch时做commit。需要小心的是批处理失败的情况:如果关闭auto commit,当发生错误时,可以调用rollback进行回滚,也可以调用commit提交成功执行的那部分修改;但如果打开auto commit,如何处理由实现(驱动)决定。因此,在执行批处理时,应当总是关闭auto commit。

 

Oracle 9i特性中,给出了一些最佳实践,包括:

1.  在执行批处理时,总是关闭auto commit;

2.  Batch的大小应保持在10左右;

 

Oracle后续的版本(10g/11g),也要求关闭auto commit。但是,在11g中,推荐的batch大小介于50到100之间。

Oracle recommends you to keep the batch sizes in the general range of 50 to 100. This is because though the drivers support larger batches, they in turn result in a large memory footprint with no corresponding increase in performance. Very large batches usually result in a decline in performance compared to smaller batches.

Oracle在批处理上还有些其它限制,具体可以参考文后的链接。我们可能不需要关注这样的细节,最好咨询DBA。

 

二.update和executeBatch返回值

iBatis SqlMap文档提到,批处理执行时,JDBC驱动可以不返回更新的记录数。所以在批处理中,不要依赖update、delete、updateBatch等方法的返回值。

Note that it is entirely legal for the JDBC driver to fail to return the number of records updated in a batch - in which case the executeBatch() method will return 0 even though records have been updated. The Oracle driver is a good example of a driver that behaves this way.

但是,如果一条insert语句的sqlMap定义了selectKey语句,批处理中的insert仍然会正确返回主键值,因为SelectKeyStatement是在批处理外进行的。请参考SqlMapExecutorDelegate#insert。

 

三.batch与事务

批处理必须总是包裹在一个显式的事务中,否则iBatis会无视batch,逐条执行。请参考SqlMapExecutorDelegate#insert。

A batch should ALWAYS be nested inside an explicit transaction. If you fail to use an explicit transaction, then iBATIS will execute each statement individually as if you had never started a batch.

在使用到批处理时,我们通常在DAO这样写:

getSqlMapClientTemplate().execute(new SqlMapClientCallback() {

 

    public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {

        executor.startBatch();

        for (QuotationItemTemplateDO template : quotationItemTemplates) {

            executor.insert("MS-CREATE-QUOT-ITEM-TEMPLATE", template);

        }

        executor.executeBatch();

        returnnull;

    }

});

SqlMapClientTemplate会自动包裹一个UserProvidedTransaction,不过遗憾的是,这个事务不会关闭auto commit。所以我们还是需要在Biz层包裹一个Spring管理的事务。请参考DataSourceTransactionManager#doBegin,这个方法关闭了auto commit。

 

四.参考

²  JDBC 3.0 Spec: http://cds.sun.com/is-bin/INTERSHOP.enfinity/WFS/CDS-CDS_Developer-Site/en_US/-/USD/VerifyItem-Start/jdbc-3_0-fr-spec.pdf?BundledLineItemUUID=TBGJ_hCujZcAAAEpc8FCxpJr&OrderID=ugmJ_hCukvUAAAEpZcFCxpJr&ProductID=eKnACUFBKakAAAEYLrU5AXiq&FileName=/jdbc-3_0-fr-spec.pdf

²  Oracle 9i Feature:

http://www.oracle.com/technology/products/oracle9i/daily/jun07.html

²  Oracle 10g – Performance Extensions:

http://download.oracle.com/docs/cd/B19306_01/java.102/b14355/oraperf.htm#i1059053

²  Oracle 11g – Performance Extensions:

http://download.oracle.com/docs/cd/E11882_01/java.112/e10589/oraperf.htm#i1056232

²  iBatis SqlMap Document:

http://svn.apache.org/repos/asf/ibatis/java/ibatis-2/trunk/ibatis-2-docs/en/iBATIS-SqlMaps-2_en.pdf

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值