用户組用户角色應用關係綁定,先取最終用户需要綁定角色的交併集,然後再求用户組用户角色的笛卡爾積,最多可產生(用户數應用數角色數)條數據,多線程操作,從幾小時到幾十分鐘,增加一個查詢(open_role_user表的user_id)索引,變成6分鐘,改成批處理插入,變成秒級處理,之前是因為jpa在多線程環境下有問題(使用threadlocal維護本身context,默認使用open-view-intercepter來維護線程級別的context),後來通過jdbctemplate重寫,自定義事務範圍
後來做了減法,因為最終生成的就是用户和角色的關聯關係,是一張中間表,就一個user_id和role_id的聯合主鍵,之前是批量插入,jdbctemplate的批量插入是直接按list的size進行設置,不過批量數據5000多個用户的用户組多綁定幾個角色的話就達到12w+級別,即使批量插入(批量插入這步操作單線程了,所以cpu看監控都是比較少的80%左右的利用率,前面計算交併集的時候程序和mysql都能達到500%左右的利用率)也需要耗時
所以這裏我嘗試進行了優化,因為mysql的插入,對於設置了主鍵且主鍵不一樣的情況下,不會產生衝突(只會生成一個IX表鎖和REC_NOT_GAP當前記錄的行鎖),所以我改成使用多線程插入
但是需要面臨的一個問題就是jdbctemplate的事務傳播問題,因為spring的事務傳播原理底層是使用的threadlocal,單線程環境下事務沒有問題,而多線程使用並行流或者線程池就讀不到上下文了,所以這裏我需要做下調整,可以先切分數據list為多份然後循環使用最原生的thread執行批量操作(這裏需要自己通過InheritableThreadLocal來綁定子線程的connection,spring默認使用的是ThreadLocal,不支持子線程上下文共享),再通過CountDownLatch來實現線程執行等待效果
結果發現多線程插入和單線程插入同一張表花費的時間幾乎差不多,都是60s左右,具體原因可能是因為即使我多線程批量插入,但是我為了保持一個事務,所以只能共用一個connection,所以最終發送到mysql的還是一樣的效果
後面我又找了一下有沒有提升批量插入速度的方案,今天又發現一個jdbc批處理的參數rewriteBatchedStatements,會改批量sql(insert into xxx value(xxx))為拼接sql(insert into xxx values(xx),(xxx)),效率極大提升,基本執行12w+的數據插入只要2s,提升一個數量級