用户组用户角色应用关系绑定批量插入应用用户和应用角色关联关系数据(后续)

用户组用户角色应用关系绑定,先取最终用户需要绑定角色的交并集,然后再求用户组用户角色的笛卡尔积,最多可产生(用户数应用数角色数)条数据,多线程操作,从几小时到几十分钟,增加一个查询(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,提升一个数量级

你可能感兴趣的:(用户组用户角色应用关系绑定批量插入应用用户和应用角色关联关系数据(后续))