数据量大的情况下批量处理总结

记得在第一家公司做一个需求时,遇到了数据库瓶颈,一条查询视图的SQL老是超时,放在现在估计是看索引,看SQL分析了像这样:
SQL分析.png

然而当时不懂这些啊,就是记得好像是因为in后面的数据太多了,超过1000就奇差无比,我记得当时百度了N多资料,让我整出了for循环每1000条就and拼接的玩法,像这样:

            StringBuilder sb = new StringBuilder();
    for (int i = 0; i < numberList.size(); i++) {
        if ((i % 1000) == 0 && i > 0) {
            sb.deleteCharAt(sb.length() - 1);
                             // resolved ORA-01795 problem.
            sb.append(") OR  number IN ( '" + numberList.get(i) + "',");
        } else {
            sb.append("'" + numberList.get(i) + "',");
        }
    }
            // delete the last comma    
            sb.deleteCharAt(sb.length() - 1); 
    String sql = "select *,*from table where number in ("
            + sb.toString()
            + ") and ....";

很傻吧,但是最近做的项目却用到了这里的一段,这也再次提醒我积累的重要性,首先,这次的需求大概是处理照片的,涉及到文件io操作这块确实很痛苦啊,哦跑偏题了,回到正题,还记得我遇到的第一个坑就是在for循环里一遍一遍操作数据库,所以我现在写插入都是这样的:

dateMapper.batchInsert(new ArrayList<data>() {{add(oneData); }});


/**
 * 批量插入
 *
 * @param dataList
 */
void batchInsert(@Param("dataList") List<data> dataList);

  <insert id="batchInsert">
    INSERT INTO table (ID,*,CREATE_TIME, MODIFY_TIME)
    VALUES
    <foreach collection="dataList" item="data" index="index" separator=",">
        (
        #{data.*},
        now(),
        now()
        )
    </foreach>
</insert>

看到没,就算只一条一条插入我也写成支持批量插入的:)

然而比较尴尬的事情是,因为这个业务是有调用其他服务的,如果数据量一大(比如1万条或10万条),其他服务就挂了,而且传参也会超出长度的不是吗?,所以就有了上面积累下来的代码的作用了,我拆成50条每次去批量调接口就没有问题了。这里涉及到异步
异步.png

,事务
事务.png

,分布式事务等问题,就不细说了,说回批量的实现,借助了一开始的代码,实现如下:

@Async
public void add( List<data> dataAddList) {
    if (CollectionUtils.isNotEmpty(dataAddList)) {
        StringBuilder sb = new StringBuilder();
        int size = dataAddList.size();
        for (int i = 0; i < dataAddList.size(); i++) {
            sb.append(dataAddList.get(i).getId());
            sb.append(",");
            if (i > 0 && (i % 50) == 0) {
                size -= 50;
                int batch = i / 50;
                batchAdd(dataAddList.subList((batch - 1) * 50, batch * 50), sb.deleteCharAt(sb.length() - 1).toString());
                sb = new StringBuilder();
            }
            if (size < 50) {
                for (int j = 0; j < size - 1; j++) {
                    sb.append(dataAddList.get(i + j).getId());
                    sb.append(",");
                }
                batchAdd( dataAddList.subList(i, dataAddList.size()), sb.deleteCharAt(sb.length() - 1).toString());
                return;
            }
        }
    }
}

顺便安利几个项目里用到的io方法吧,真的感觉还挺好用的:

//移动文件到目录
FileUtils.moveFileToDirectory(file, directory, true);
// 追加写入by FileUtils
FileUtils.writeStringToFile(file, string, "utf-8", true);
打开一个文件流
FileInputStream Input = FileUtils.openInputStream(file);
然后是因为发送文件只能发送MultipartFile 就用测试mock了一个发过去
MultipartFile multipartFile = new MockMultipartFile("file", file.getName(), "text/plain", IOUtils.toByteArray(Input));

String md5 = DigestUtils.md5Hex(multipartFile.getBytes());
//获取MD5,注意此处有坑,md5Hex(input)会导致mock失败只能先关流再重新开流才行,而如果先mock再获取MD5的话会导致获取的MD5值完全一致,所以我一开始是很蠢的开一遍流再关流再重新开流来解决的,后来发现用multipartFile.getBytes()替代input可以解决这个问题,至于网上的用这种input复用方法个人实验发现完全没卵用:


inputStream复用.png

说起积累,忍不住在最后闲聊几句,很多的时候,我们大部分程序员大部分时间在写些简单重复的代码,谁会天天写高并发,大数据处理,分布式架构等等高大上的东西呢?,这些大部分只是在面试的时候会问到,真写过有几个人写过呢,我相信写增删改查的时间一定占据了我们大部分时间。那就有很大培训班,网课,之类的给你安利各种高大上的技术,牛逼的架构什么的,其实我倒是觉得写好每一行代码才是正经事,每写一行代码想想若干年后可能会有人对你的代码一番吐槽,我相信你就不会为了赶时间完成任务而那么随意了,我记得潘爱民演讲的时候拿出他几十年写的一小段C语言代码,那已经成为微软底层的一部分了,我们现在在电脑上浏览这篇文章,我在编辑的时候就会用到这行代码。这是对细节上的讲究,谈回积累,很多人写了N多代码却没有任何复盘和总结,实现过就完了,下次再遇到类似希求又写一遍,有意思吗?不是说鼓励大家存工作的代码,事实上每个程序员签劳动合同的同时都会签订保密协议,在第二家公司的时候也见到过有傻子把公司代码上传到GitHub上被告到法院的例子,但这不代表你不能记笔记,不能总结,不能留存复用自己凝思苦想的结果,事实上,我在简书上写这些,也就是趁自己有空把自己做过的项目需求总结一下,回顾一下,积累一下,我觉得花半天时间总结一下做了一两个星期或几个月的项目绝对比在电脑面前看半天网课老师吹牛逼来的实际有用得多。建议各位可以像这样

第*周(yyyy.MM.dd-yyyy.MM.dd):双周
周一(yyyy.MM.dd):
周二(yyyy.MM.dd):
周三(yyyy.MM.dd):
周四(yyyy.MM.dd):
周五(yyyy.MM.dd):

写份工作日志(自己用,有日报或周报要求的也可以写)每天一句话,离职的时候,我都是直接这个一给就交接了,希望程序员路上与君共勉!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容