随着系统并发请求激增,参考电商秒杀、当下集中核酸采取等业务场景,如果突然大量数据请求业务系统。此时如果没有做任何缓存措施,直接保存数据库,即使你的数据库做了集群和分库分表,也会由于扛不住并发压力崩溃的。基于最简单的存储模型,就是用Redis做缓存,数据业务插入到Redis缓存中,然后缓存依据系统的处理能力依次批量插入数据库,就有效避免数据库崩溃的情况发生了。

        基于最简单的存储模型,就是用Redis做缓存,数据业务插入到Redis缓存中,然后缓存依据系统的处理能力依次批量插入数据库,就有效避免数据库崩溃的情况发生了。

    然后有人说:Redis就不会崩了吗?

    当然,Redis也有它的并发上限,但是Redis是基于内存的,数据库是基于硬盘的,缓存要比数据库轻量得多!

简单模型大致如下:

c redis批量写入 redis批量写入数据java_java

        核心功能是:每条数据都直接通过StringRedisTemplate下的leftPushAll方法插入缓存,然后再通过定时任务,调用rightPop方法取出指定数量的集合数据,批量持久化到数据库中。注意:插入的时候从左边插入,取的时候就要从右边取出,这样的话就跟队列一样,先进先出、依次按序保存了。

Springboot大致实现的demo如下,仅供参考

1. 建项目,导入redis、mysql的依赖,yml中做配置等

略(我用的Springboot+mybatis+mybatisPlus+mysql的项目)

2. 数据库中新建一张表用于测试,对应实体、mapper、service、controller新建

c redis批量写入 redis批量写入数据java_c redis批量写入_02

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class TempLog {
    @TableId
    private Long logId;
    private String logParam;
    private String logMsg;
    private String createTime;
}

3. controller中引入StringRedisTemplate

@Slf4j
@RestController
@RequestMapping("/temp")
public class TempLogController {

    @Autowired
    private TempLogService tempLogService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    private static final String CACHE_KEY = "TEMP_LIST";

}

4. 写一个方法,模拟数据插入,使用redis的opsForList()插入数据到缓存中

/**
     * 模拟:插入数据,单条存入到缓存集合中(从左边插入)
     */
    @GetMapping("/saveCache")
    public R saveCache(){
        TempLog tempLog = TempLog.builder().logParam(StringUtils.getUuid())
                .logMsg(StringUtils.getRandomStr(10))
                .createTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()))
                .build();
        log.info("数据插入...........");
        redisTemplate.opsForList().leftPushAll(CACHE_KEY, JSON.toJSONString(tempLog));
        return R.ok();
    }

5. 开启一个定时任务,模拟定时把缓存中的集合数据插入到数据库中

/**
     * 定时任务,把缓存中的集合数据插入到数据库中
     * 模拟:每3s执行一次,每次从缓存中取50条数据(从右边取出)
     */
    @Scheduled(cron = "*/3 * * * * ?")
    public void saveDB(){
        //注意:redis6.2.0以上才支持rightPop(key, count)方法,redis6.2.0版本以下调用rightPop(key, count)方法会报错,
        //低版本只能使用rightPop(key)单条取
        //rightPop(key, count) 返回值是List
        //rightPop(key) 返回值是String
        log.info("定时任务...........");
        List<String> list = redisTemplate.opsForList().rightPop(CACHE_KEY, 50);
        if (list != null && list.size() > 0) {
            List<TempLog> collect = list.stream().map(i -> {
                TempLog tempLog = JSON.parseObject(i, TempLog.class);
                return tempLog;
            }).collect(Collectors.toList());
            //批量插入数据库
            tempLogService.saveBatch(collect);
        }
    }

注意:redis6.2.0以上才支持rightPop(key, count)方法,redis6.2.0版本以下调用rightPop(key, count)方法会报错

6. 测试看下效果

使用Jmeter开启100个线程,循环20次,默认发起2000次请求

c redis批量写入 redis批量写入数据java_缓存_03

可以看到1秒钟,就把所有的数据都提交到缓存中了,并发量达到 2000/s 了!

c redis批量写入 redis批量写入数据java_java_04

然后缓存中的数据依次批量提交到数据库了!

完结!