性能之Hibernate大批量保存数据优化

开心一笑

【跟我妈说这几天特别郁闷,心情糟透了。
我妈说:要不我给你拿钱你出去玩几天啊!
我立马笑颜逐开:“好啊好啊”!
妈:“开心了吧”!
我:“嗯嗯,妈,快点拿钱呀!”
妈:“你都开心了我还拿钱干啥!”
我。。。】

视频教程

大家好,我录制的视频《Java之优雅编程之道》已经在CSDN学院发布了,有兴趣的同学可以购买观看,相信大家一定会收获到很多知识的。谢谢大家的支持……

视频地址:http://edu.csdn.net/lecturer/994

提出问题

真实项目中,批量插入数据性能优化???

性能之Hibernate大批量保存数据优化_第1张图片

解决问题

1.业务场景

1.1 业务描述

数据库有一张表(pm_testcase),客户有一份excel数据,里面有3+万条左右案例。现在需要解析excel里面的内容,对每条数据进行校验。比如:名称长度校验,编号校验,用户账号是否存在检验等等。然后封装成 List 集合,批量保存。

CREATE TABLE "public"."pm_testcase" (
"id" varchar(32) COLLATE "default" NOT NULL,
"code" varchar(50) COLLATE "default",
"name" varchar(200) COLLATE "default",
//....省略若干个字段
CONSTRAINT "pk_pm_testcase" PRIMARY KEY ("id")
)
WITH (OIDS=FALSE)
;

1.2 业务流程图

流程图片

2.项目现状

2.1 问题一

在excel数据导入,循环 List 集合,进行校验时,存在大量的连接数据库操作。

//循环excel的每一行
for (int j = sheet.getFirstRowNum() + 1,len = sheet.getLastRowNum(); j <= len; j++) {
    Row row = sheet.getRow(j);
    if (row == null) continue;
    if (StringUtils.isEmpty(getValue(row.getCell(6)))) resultBuffer.append("案例类型为空,");
    //....省略其他校验操作...
    //连接数据库
    SysUser sysUser = sysUserService.findById(id);
}

2.2 问题二

直接批量保存3万多条数据。

List pcsTestcases = new ArrayList<>();
// ......
//直接调用批量保存  
this.batchCreate(pcsTestcases);

2.3 问题三

批量保存时,利用UUID生成工具,给主键设置Id。找出Hibernate的先查询后更新的机制触发,造成不必要的查询损耗。

List pcsTestcases = new ArrayList<>();
PcsTestcase pcsTestcase = null;
for (int j = sheet.getFirstRowNum() + 1,len = sheet.getLastRowNum(); j <= len;j++) {
    Row row = sheet.getRow(j);
    if (row == null) continue;
    pcsTestcase = new PcsTestcase();
    //看这里,重要:这里在插入数据时,设置主键Id
    pcsTestcase.setId(UUIDUtils.generate());
    pcsTestcase.setPmMilestoneId(pcsMainTask.getId());
}

3. 解决方法

3.1 问题一解决方法

对于问题一,除了避免在 for 循环体内连接数据库外,我们可以利用 Map集合的缓存机制,把之后需要用到的数据加载到map集合中。比如:依次性查询出所有的用户数据等等,存放在Map集合中。

3.2 问题二解决方法

对于问题二,我们可以把所有数据,每500条进行一次批量保存操作,速度会比一次性批量保存好。具体如下:

if(j % 500 == 0 || j == len){
    this.batchCreate(pcsTestcases);
    pcsTestcases = new ArrayList<>();
}

3.3 问题三解决方法

对于问题三,由于Hibernate在进行插入时,会判断数据是进行插入还是进行更新。如果模型的主键不为空,查询数据后,再进行更新数据,否则,进行插入数据操作。因此,我们在进行插入操作时候,不要设置模型的主键,可以避免不必要查询消耗。

pcsTestcase.setId(UUIDUtils.generate());

基本的优化思路就是这样了,大功告成~~~

读书感悟

来自北宋名相寇准《六悔铭》,教人要及早觉悟悔改

  • 六悔铭
    官行私曲,失时悔。
    富不俭用,贫时悔。
    艺不少学,过时悔。
    见事不学,用时悔。
    醉发狂言,醒时悔。
    安不将息,病时悔。

经典故事

【一教授与农民在火车上相对而坐,无聊之际。教授说:我出一道题,你若不知,给我5元,如果你出一道题,我若不知,给你500元如何?农民同意。教授问:月亮距地球多远?农民一言不发递给教授5元。农民问:上山三条腿,下山四条腿,是什么动物?教授苦思无解,无奈给农民500元。农民接过钱准备睡觉。教授追问:上山三条腿,下山四条腿究竟是什么动物?农民一言不发递给教授5元钱,然后睡觉了。低学历高智商,太可怕了!这就是许多没学历的人能成为老板,首富的原因。】

大神文章

【1】【Java/JDBC.ORM】 jdbc插入大量数据时优化处理
【2】Hibernate批处理操作优化 (批量插入、更新与删除)
【3】用Java向数据库中插入大量数据时的优化

其他

如果有带给你一丝丝小快乐,就让快乐继续传递下去,欢迎点赞、顶、欢迎留下宝贵的意见、多谢支持!

你可能感兴趣的:(一步一步学性能优化)