性能之Hibernate大批量保存數(shù)據(jù)優(yōu)化

開心一笑

【跟我媽說(shuō)這幾天特別郁悶,心情糟透了。
我媽說(shuō):要不我給你拿錢你出去玩幾天??!
我立馬笑顏逐開:“好啊好啊”!
媽:“開心了吧”!
我:“嗯嗯,媽,快點(diǎn)拿錢呀!”
媽:“你都開心了我還拿錢干啥!”
我。。?!?/p>

提出問(wèn)題

真實(shí)項(xiàng)目中,批量插入數(shù)據(jù)性能優(yōu)化???

唯美圖片

解決問(wèn)題

1.業(yè)務(wù)場(chǎng)景

1.1 業(yè)務(wù)描述

數(shù)據(jù)庫(kù)有一張表(pm_testcase),客戶有一份excel數(shù)據(jù),里面有3+萬(wàn)條左右案例?,F(xiàn)在需要解析excel里面的內(nèi)容,對(duì)每條數(shù)據(jù)進(jìn)行校驗(yàn)。比如:名稱長(zhǎng)度校驗(yàn),編號(hào)校驗(yàn),用戶賬號(hào)是否存在檢驗(yàn)等等。然后封裝成 List 集合,批量保存。

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

1.2 業(yè)務(wù)流程圖

流程圖片

2.項(xiàng)目現(xiàn)狀

2.1 問(wèn)題一

在excel數(shù)據(jù)導(dǎo)入,循環(huán) List 集合,進(jìn)行校驗(yàn)時(shí),存在大量的連接數(shù)據(jù)庫(kù)操作。

//循環(huán)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("案例類型為空,");
    //....省略其他校驗(yàn)操作...
    //連接數(shù)據(jù)庫(kù)
    SysUser sysUser = sysUserService.findById(id);
}

2.2 問(wèn)題二

直接批量保存3萬(wàn)多條數(shù)據(jù)。

List<PcsTestcase> pcsTestcases = new ArrayList<>();
// ......
//直接調(diào)用批量保存  
this.batchCreate(pcsTestcases);

2.3 問(wèn)題三

批量保存時(shí),利用UUID生成工具,給主鍵設(shè)置Id。找出Hibernate的先查詢后更新的機(jī)制觸發(fā),造成不必要的查詢損耗。

List<PcsTestcase> 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();
    //看這里,重要:這里在插入數(shù)據(jù)時(shí),設(shè)置主鍵Id
    pcsTestcase.setId(UUIDUtils.generate());
    pcsTestcase.setPmMilestoneId(pcsMainTask.getId());
}

3. 解決方法

3.1 問(wèn)題一解決方法

對(duì)于問(wèn)題一,除了避免在 for 循環(huán)體內(nèi)連接數(shù)據(jù)庫(kù)外,我們可以利用 Map集合的緩存機(jī)制,把之后需要用到的數(shù)據(jù)加載到map集合中。比如:依次性查詢出所有的用戶數(shù)據(jù)等等,存放在Map集合中。

3.2 問(wèn)題二解決方法

對(duì)于問(wèn)題二,我們可以把所有數(shù)據(jù),每500條進(jìn)行一次批量保存操作,速度會(huì)比一次性批量保存好。具體如下:

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

3.3 問(wèn)題三解決方法

對(duì)于問(wèn)題三,由于Hibernate在進(jìn)行插入時(shí),會(huì)判斷數(shù)據(jù)是進(jìn)行插入還是進(jìn)行更新。如果模型的主鍵不為空,查詢數(shù)據(jù)后,再進(jìn)行更新數(shù)據(jù),否則,進(jìn)行插入數(shù)據(jù)操作。因此,我們?cè)谶M(jìn)行插入操作時(shí)候,不要設(shè)置模型的主鍵,可以避免不必要查詢消耗。

pcsTestcase.setId(UUIDUtils.generate());

基本的優(yōu)化思路就是這樣了,大功告成~~~

讀書感悟

來(lái)自北宋名相寇準(zhǔn)《六悔銘》,教人要及早覺悟悔改

  • 六悔銘
    官行私曲,失時(shí)悔。
    富不儉用,貧時(shí)悔。
    藝不少學(xué),過(guò)時(shí)悔。
    見事不學(xué),用時(shí)悔。
    醉發(fā)狂言,醒時(shí)悔。
    安不將息,病時(shí)悔。

經(jīng)典故事

【一教授與農(nóng)民在火車上相對(duì)而坐,無(wú)聊之際。教授說(shuō):我出一道題,你若不知,給我5元,如果你出一道題,我若不知,給你500元如何?農(nóng)民同意。教授問(wèn):月亮距地球多遠(yuǎn)?農(nóng)民一言不發(fā)遞給教授5元。農(nóng)民問(wèn):上山三條腿,下山四條腿,是什么動(dòng)物?教授苦思無(wú)解,無(wú)奈給農(nóng)民500元。農(nóng)民接過(guò)錢準(zhǔn)備睡覺。教授追問(wèn):上山三條腿,下山四條腿究竟是什么動(dòng)物?農(nóng)民一言不發(fā)遞給教授5元錢,然后睡覺了。低學(xué)歷高智商,太可怕了!這就是許多沒(méi)學(xué)歷的人能成為老板,首富的原因?!?/p>

大神文章

【1】【Java/JDBC.ORM】 jdbc插入大量數(shù)據(jù)時(shí)優(yōu)化處理
【2】Hibernate批處理操作優(yōu)化 (批量插入、更新與刪除)
【3】用Java向數(shù)據(jù)庫(kù)中插入大量數(shù)據(jù)時(shí)的優(yōu)化

其他

如果有帶給你一絲絲小快樂(lè),就讓快樂(lè)繼續(xù)傳遞下去,歡迎點(diǎn)贊、頂、歡迎留下寶貴的意見、多謝支持!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容