ibatis批量插入数据

写在前面

最近在项目中需要一次性插入大批量数据到数据库,如果使用传统for循环方式一条记录一条记录地插入显然效率太低,而且大大增加了数据库的开销,因为每执行一次insert操作都要创建一次数据库连接。于是,想到了ibatis的批处理方法。

网上找了很多资料,大同小异,总结了一下,主要有一下两种方式:

  • 在xml文件中使用iterator标签或foreach标签拼接sql
  • 使用sqlMapClient提供的一组批处理方法
使用xml拼接sql

xml代码如下:

<insert id="insertData" parameterClass="java.util.List">
        insert into batchinsert_test(id,
              studentid,
              schoolid,
              schoolname,
              supplierid,
              countryid,
              major,
              payerid,
              schinesename,
              senglishsurname
        ) 
        select hibernate_sequence.nextval, t.* from (  // 使用序列生成主键
            <iterate conjunction=" union all " > // conjunction属性表示每次循环结束添加的字符
                select 
                       #list[].studentid#,  // list为传入的参数名称
                       #list[].schoolid#,
                       #list[].schoolname#,
                       #list[].supplierid#,
                       #list[].countryid#,
                       #list[].major#,
                       #list[].payerid#,
                       #list[].schinesename#,
                       #list[].senglishsurname#
                from dual
            </iterate>
        ) t
</insert>

注意:此语法只支持Oracle,不支持mysql,mysql的自行百度,原理是一样的,只是语法不一样

调用代码如下:

@Override
    public void insertData(List<batchInsertEntity> list) {
        try {
            this.sqlMapClient.insert("OrderformImport.insertData", list);
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

测试发现,使用xml拼接sql的方式实现批量插入数据有一个问题,当批量插入的数据量太大(我的是超过5000条数据),会报“无效的主机/绑定变量名”异常,原因未明,还望知道的大神不吝赐教,楼主不胜感激。

使用sqlMapClient提供的批处理方法

ibatis通过sqlMapClient提供了一组方法用于实现批处理:

  • startBatch():开始批处理
  • executeBatch():执行批处理

为了避免事务代码的入侵,把事务完全交给Spring统一处理,我们使用Spring的回调模式去实现:

首先你的dao需要继承SqlMapClientDaoSupport类,或者在你的dao中将sqlMapClient注入到sqlMapClientTemplate中,然后调用sqlMapClientTemplate的execute方法,覆写SqlMapClientCallback类中的doInSqlMapClient方法

@Repository("testDao")
public class TestDaoImpl extends SqlMapClientDaoSupport implements TestDao {

    @Override
    public void insertBatchData(final List<batchInsertEntity> list) {
        // list入参必须声明为final,不能被修改
        // 执行回调
        getSqlMapClientTemplate().execute(new SqlMapClientCallback<Object>() {
            //实现回调接口
            @Override
            public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
                int batch = 0;
                executor.startBatch();// 开始批处理
                for (batchInsertEntity entity : list) {
                    batch++;
                    executor.insert("OrderformImport.insertData2", entity);
                    //每100条提交一次
                    if (batch%100 == 0) {//Oracle 11g推荐的batch大小介于50-100之间
                        executor.executeBatch();
                        executor.startBatch();
                    }
                }
                executor.executeBatch();// 执行批处理

                return null;
            }
        });
    }
}

最终可能抛出的异常:DataAccessException

<insert id="insertData2" parameterClass="com.iss.itreasury.cbeservice.transaction.orderformimport.web.batchInsertEntity">
        <selectKey resultClass="Long" type="pre" keyProperty="id">
            select hibernate_sequence.nextval from dual
        </selectKey>

        insert into batchinsert_test(id,
            studentid,
              schoolid,
              schoolname,
              supplierid,
              countryid,
              major,
              payerid,
              schinesename,
              senglishsurname
        )
        values(#id#,
            #studentid#,
              #schoolid#,
              #schoolname#,
              #supplierid#,
              #countryid#,
              #major#,
              #payerid#,
              #schinesename#,
              #senglishsurname#
        )
    </insert>

测试了10万条数据,导入正常,耗时大概4分钟多点,在实际项目中,如果数据量大,建议每1000条(这个根据自己的实际情况自己定)就做一次批量导入,这样效率会比一次性批量导入高很多。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值