• iBatis批量插入1万多条数据,出错后继续执行剩下的代码


    翻了很多大佬的博文,得到觉得最佳的方式:基于回调的方式

    回调接口 SqlMapClientCallback,这个是没有事务的。

    这里有一位大佬对iBatis源码的解析:

    https://www.cnblogs.com/jdluojing/p/4201832.html#4686042

    由于这个是直接操作数据库的,所以我写在DAO层。

    我想要实现的需求:

      数据源是从一个接口一次性获得到的,这个不改;

      然后批量入库,出错后继续执行剩下的代码!

     sqlMapClientTemplate.execute(new SqlMapClientCallback(){
                @Override
                public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
    
                    executor.startBatch();
                    int count = 1; //记录操作的数量
                    Account account= new account();
                    for(CustResponse custRes : custResponseList) {
                        account.setAcctId(custRes.getAcctId());
                        account.setCustId(custRes.getCustId());
                        account.setCustName(custRes.getCustName());
                        executor.insert(sqlName, account);//sqlName="com........Account.mergeIntoAccount"
                        try {
                            if (count % AccountTblImpl.BATCH_NUM == 0) {  //AccountTblImpl.BATCH_NUM = 50
                                executor.executeBatch();
                                executor.startBatch();
                            }
                        } catch (Exception e) {
                            LOG.error("定时同步数仓数据: 第" + (count-AccountTblImpl.BATCH_NUM+1) + "-" + count + "数据入库发生异常!", e);
                            printErrorCustList(custResponseList, count-AccountTblImpl.BATCH_NUM, count);
                        }
                        count++;
                    }
                    try {
                        executor.executeBatch();
                    } catch (Exception e) {
                        int fromIndex = count/AccountTblImpl.BATCH_NUM*accountTblImpl.BATCH_NUM;
    
                        LOG.error("定时同步数仓数据: 第" + (fromIndex+1) + "-" + (count-1) + "数据入库发生异常!", e);
                        printErrorCustList(custResponseList, fromIndex, count-1);
                    }
                    //Oracle没有办法知道batch中某语句确切影响的记录数,而JDBC 2.0规范规定,操作成功但影响行数不确定的
                    //所以executor.executeBatch() 返回0
                    return 0;
                }
            });
    //这个是后面加的,因为实在没有找到办法可以定位到发生异常的那条数据,所以把发生异常的这个批次全部记录打印出来
    public void printErrorCustList(List<CustResponse> custResponseList, int fromIndex, int toIndex) {
       List<CustResponse> errorCustList = custResponseList.subList(fromIndex, toIndex);
       LOG.error("发生异常的这批数据:" + errorCustList);
    }

    1w多条数据,正常执行的时间是在34秒-37秒,在服务器上跑也是正常情况。

    Oracle数据操作代码

    <statement id="mergeIntoAccount" parameterClass="AccountClass">
        MERGE INTO ACCOUNT
        USING (
            select count(1) co from ACCOUNT where ACCT_ID = #acctId:VARCHAR#
        ) S ON ( S.co = 1 )
        WHEN MATCHED THEN
        update set
            CUST_ID = #custId:VARCHAR#,
            CUST_NAME = #custName:VARCHAR#,
            UPDATE_TIME = to_timestamp(to_char(sysdate,'YYYY-MM-DD HH24:MI:SS'),'YYYY-MM-DD HH24:MI:SS')
            WHERE ACCT_ID = #acctId:VARCHAR#
        WHEN NOT MATCHED THEN
        INSERT (
            ACCT_ID, CUST_ID, CUST_NAME, UPDATE_TIME
        ) VALUES (
            #acctId:VARCHAR#, #custId:VARCHAR#, #custName:VARCHAR#,
            to_timestamp(to_char(sysdate,'YYYY-MM-DD HH24:MI:SS'),'YYYY-MM-DD HH24:MI:SS')
        )
    </statement>

     对比下一条一条插入: 1w多条数据插入时间为65秒左右;

    不知道为什么放到服务器上,耗时变为7-8min,所以就放弃了这种方法。

    iBatis批处理的话,BATCH_NUM 为500时,也要60秒每次,越大时间越短。

    我自己测试是这样的。10000条/批的时候是38秒左右。

    --------------------------------- 以下是自己作的流程,仅供自己回忆-----------------------------------------

    那么问题来了,我查不到这个批处理在并发的情况下会是什么情况?

    然后我手动设置了3个错误的数据:

    List<CustResponse> List = custListRes.getData();
    CustResponse c = List.get(9);
    LOG.error("即将出错的数据:" + c);
    c.setAcctId(null);
    CustResponse c2
    = List.get(1000); LOG.error("即将出错的数据:" + c2); c2.setAcctId(null);
    CustResponse c3
    = List.get(13101); LOG.error("即将出错的数据:" + c3); c3.setAcctId(null);

    单单测试这段代码是按照预期想法来的,以下是log日志:

    //dao层日志
    定时同步数仓数据: 第1-50数据入库发生异常! 定时同步数仓数据: 第1001-1050数据入库发生异常! 定时同步数仓数据: 第13101-13102数据入库发生异常!

    //service层日志
    定时同步数仓数据[通过iBatis批处理]—执行完毕!耗时:36秒

    然后这段业务是个定时任务,因为项目中还有其他6,7个定时任务在跑,这些任务都有对这个数据表进行操作,

    然后这个批处理就扛不住了,输出了第二段错误日志后【定时同步数仓数据: 第1001-1050数据入库发生异常!】

    就没有反应了,隔了很久才打出最后结束的日志(当场狗带)

     不知道为什么,批处理出现异常后,性能天差地别。

    下班时间到了,又搞了2小时,才发现当时卡主是因为本地在跑,服务器也在跑,都是在做插入操作!

    本地停了之后,服务器的日志打印的时间就恢复正常了!唉......

  • 相关阅读:
    【杂谈】压行技巧(压代码)
    【UVA】11464 Even Parity(枚举子集)
    【POJ】2373 Dividing the Path(单调队列优化dp)
    【POJ】2329 Nearest number
    【BZOJ】1833: [ZJOI2010] count 数字计数(数位dp)
    【BZOJ】2809: [Apio2012]dispatching(左偏树)
    【BZOJ】2342: [Shoi2011]双倍回文(Manacher)
    【BZOJ】1912: [Apio2010]patrol 巡逻(树的直径)
    【BZOJ】1911: [Apio2010]特别行动队(斜率优化dp)
    【BZOJ】1913: [Apio2010]signaling 信号覆盖(计算几何+计数)
  • 原文地址:https://www.cnblogs.com/hxliang/p/13687196.html
Copyright © 2020-2023  润新知