Redis打包事务,分批提交

一、需求背景

      接手一个老项目,在项目启动的时候,需要将xxx省整个省的所有区域数据数据、以及系统字典配置逐条保存在Redis缓存里面,这样查询的时候会更快;
      区域数据+字典数据一共大概20000多条,,前同事直接使用 list.forEach()逐条写入Redis,如下:

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
/*** @author xxx* @version 1.0* @date 2022/7/21 15:29* @Description: 项目启动成功后初始化区域数据到redis*/
@Component
@Slf4j
public class AreasInitialComponent implements ApplicationRunner {@AutowiredprivateAreaMapper areaMapper;private static boolean isStart = false;/*** 项目启动后,初始化字典到缓存*/@Overridepublic void run(ApplicationArguments args) throws Exception {if (isStart) {return;}try {log.info("Start*******************项目启动后,初始化字典到缓存*******************");QueryWrapper<Area> wrapper = new QueryWrapper<>();wrapper.eq("del", "0");List<Area> areas = areaMapper.selectList(wrapper);if (!CollectionUtils.isEmpty(areas )) {RedisCache redisCache = SpringUtils.getBean(RedisCache.class);//先将区域集合整体做个缓存log.info("*******************先将区域集合整体做个缓存*******************");AreaUtil.setAreaListCache(redisCache, areas);//再将每一条区域进行缓存areas.stream().forEach(a -> {AreaUtil.setAreaCache(redisCache, a.getId(), a);});}isStart = true;log.info("End*******************项目启动后,初始化字典到缓存*******************");}catch (Exception e) {e.printStackTrace();}}
}

image.png

导致项目启动速度巨慢,再加上需要使用代理软件才能连接公司的数据库,每次启动项目都需要10几分钟,当真是苦不堪言;由于受不了这样的启动速度,因此决定自己动手优化。

二、解决思路

      联想到MySQL的事务打包方式,于是自己动手尝试通过Redis打包事务+分批提交的方式来提高启动速度,具体实现如下:

三、实现方法

  1. 实现方法
   @Autowiredpublic RedisTemplate redisTemplate;  /*** 逐条设置区域缓存** @param areas* @throws InterruptedException*/public void setAreaCacheItemByItem(List<Area> areas) throws InterruptedException {MoreThreadCallBack<Area> callBack = new MoreThreadCallBack<>();callBack.setThreadCount(10);callBack.setLimitCount(50);callBack.setTitle("设置区域缓存批量任务");callBack.setAllList(areas);callBack.call((list, threadNum) -> {//使用自定义线程回调工具分摊任务redisTemplate.execute(new SessionCallback<Object>() {@Overridepublic Object execute(RedisOperations operations) throws DataAccessException {//开启redis事务operations.multi();list.forEach(item -> {operations.opsForValue().set(item.getId(), item);});// 提交事务operations.exec();return null;}});});}
  1. 线程回调工具MoreThreadCallBack()
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;@Data
@Slf4j
public class MoreThreadCallBack<P> {public int limitCount = 1000;private int threadCount = 10;private List<P> allList;private AtomicInteger errorCheck;private String title;public interface CallBack<P> {void call(List<P> list, Integer threadNum);}public boolean call(CallBack<P> callBack) throws InterruptedException, RuntimeException {if (allList.isEmpty()) {return false;}// 线程池ExecutorService exec = Executors.newCachedThreadPool();// 根据大小判断线程数量if (allList.size() <= limitCount) {threadCount = 1;}// 等待结果类final CountDownLatch countDownLatch = new CountDownLatch(threadCount);// 分摊多份List<List<P>> llist = Lists.newArrayList();for (int i = 0; i < threadCount; i++) {llist.add(Lists.newArrayList());}int index = 0;for (P p : allList) {llist.get(index).add(p);index = index == (threadCount - 1) ? 0 : index + 1;}// 异常记录errorCheck = new AtomicInteger(0);// 执行for (int i = 0; i < llist.size(); i++) {List<P> list = llist.get(i);final Integer threadNum = i;exec.execute(() -> {long startTime = System.currentTimeMillis();//抛出异常 自身不处理log.info("标题:{}-{}号线程开始回调执行 数量:{}", this.getTitle(), threadNum, list.size());callBack.call(list, threadNum);long endTime = System.currentTimeMillis();log.info("标题:{}-{}号线程回调执行完毕 耗时:{}", this.getTitle(), threadNum, +(endTime - startTime));countDownLatch.countDown();});}// 等待处理完毕countDownLatch.await();// 关闭线程池exec.shutdown();return errorCheck.get() <= 0;}public boolean next() {// 检测是否有线程提前结束if (errorCheck.get() > 0) {return false;}return true;}public void error() {errorCheck.incrementAndGet();}public String getTitle() {return title == null ? "" : title;}
}
  1. 经过如上处理以后,项目启动速度大大提升,由原本的10几分钟缩短至1分钟左右,成果如下:
    image.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/212877.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mac mysql连接中断重新启动办法

遇到如图所示问题&#xff0c;可以用下面的命令重启mysql服务 sudo /usr/local/mysql/support-files/mysql.server start

【Spring Cloud实战】分布式系统控制与组件应用

在现代软件开发中&#xff0c;分布式系统已经成为一种常见的架构模式&#xff0c;被广泛应用于各种规模的企业和组织中。这种架构模式通过将应用程序拆分为独立的组件&#xff0c;并分布在不同的计算机节点上运行&#xff0c;使得系统能够应对高负载和大规模的数据处理需求&…

竞赛 题目:基于深度学习的图像风格迁移 - [ 卷积神经网络 机器视觉 ]

文章目录 0 简介1 VGG网络2 风格迁移3 内容损失4 风格损失5 主代码实现6 迁移模型实现7 效果展示8 最后 0 简介 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于深度学习卷积神经网络的花卉识别 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c…

NSGA-III求解微电网多目标优化调度(MATLAB)

一、NSGA-III简介 NSGA-III算法由Kalyanmoy Deb和Himanshu Jain于 2014年提出。 参考文献&#xff1a;Deb K , Jain H . An Evolutionary Many-Objective Optimization Algorithm Using Reference Point-Based Nondominated Sorting Approach, Part I: Solving Problems With …

在openSUSE-Leap-15.5-DVD-x86_64中使用deepin-wine-6.0.0.19再使用金山打字通2016

在openSUSE-Leap-15.5-DVD-x86_64中使用deepin-wine-6.0.0.19再使用金山打字通2016 在openSUSE Software官网输入关键字deepin-wine搜索得到fedora-deepin-wine6的作者是xuthus5 https://software.opensuse.org/package/fedora-deepin-wine6 在百度贴吧fedora吧的《fedora下的…

MySQL错误之ONLY_FULL_GROUP_BY

报错信息&#xff1a; 翻译&#xff1a; 对该报错的解释 所以&#xff0c;实际上该报错是由于在SQL查询语句中有group by&#xff0c;而这个包含group by的SQL查询写的并不规范导致的&#xff0c;这个ONLY_FULL_GROUP_BY模式开启之后检查就会很严格&#xff0c;如果select列表…

微信小程序制作

如果你也想搭建一个小程序&#xff0c;但不知道如何入手&#xff0c;那么今天我就教你如何使用第三方制作平台&#xff0c;在短短三十分钟内搭建一个小程序。 一、登录小程序制作平台 首先&#xff0c;登录到小程序制作平台的官方网站或应用程序&#xff0c;进入后台管理系统。…

spark数据倾斜的解决思路

数据倾斜是&#xff1a;多个分区中&#xff0c;某个分区的数据比其他分区的数据多的多 数据倾斜导致的问题&#xff1a; 导致某个spark任务耗时较长&#xff0c;导致整个任务耗时增加&#xff0c;甚至出现OOM运行速度慢&#xff1a;主要发生在shuffle阶段&#xff0c;同样的k…

【数字信号处理】傅里叶变换的离散性与周期性

傅里叶变换的离散性与周期性 2023年11月21日 #elecEngeneer 文章目录 傅里叶变换的离散性与周期性1. 符号说明2. 具体分析3. 序列的序号表示的DFT下链 1. 符号说明 t : 连续时间(时域)变量 ω : 频域变量&#xff0c;aka角频率 g : 时域函数 G : 频域函数 n : 时域采样序列序号…

Qt/QML编程学习之心得:一个Qt工程的学习笔记(九)

1、.pro文件 加CONFIG += c++11,才可以使用Lamda表达式(一般用于connect的内嵌槽函数) 2、QWidget 这是Qt新增加的一个类,基类,窗口类,QMainWindow和QDialog都继承与它。 3、Main函数 QApplication a应用程序对象,有且仅有一个 a.exec() 进行消息循环、阻塞 MyWi…

Maven 简单配置阿里云镜像

配置步骤&#xff1a; 1、找到 maven 的安装目录&#xff0c;修改settings.xml 2、在文件中找到<mirrors>标签&#xff0c;然后再标签中添加阿里云配置即可 <mirror><id>aliyunmaven</id><mirrorOf>*</mirrorOf><name>阿里云公共…

基于5G+物联网+SaaS+AI的农业大数据综合解决方案:PPT全文44页,附下载

关键词&#xff1a;智慧农业大数据&#xff0c;5G智慧农业&#xff0c;物联网智慧农业&#xff0c;SaaS智慧农业&#xff0c;AI智慧农业&#xff0c;智慧农业大数据平台 一、智慧农业大数据建设背景 1、应对全球人口快速增长带来的粮食生产压力&#xff0c;未来的粮食生产力必…