[Redis] Redis实战
创始人
2024-02-01 16:08:50

✨✨个人主页:沫洺的主页

📚📚系列专栏: 📖 JavaWeb专栏📖 JavaSE专栏 📖 Java基础专栏📖vue3专栏 

                           📖MyBatis专栏📖Spring专栏📖SpringMVC专栏📖SpringBoot专栏

                           📖Docker专栏📖Reids专栏📖MQ专栏📖SpringCloud专栏     

💖💖如果文章对你有所帮助请留下三连✨✨

💌RedisTemplate使用Scan 

@SpringBootTest
public class AppTests_Scan {@Resource(name = "redisTemplate")private ValueOperations valueOperations;@Autowiredprivate StringRedisTemplate stringRedisTemplate;@Testvoid test1() {for (int i =1 ;i<11;i++){User user = User.builder().name(i+"号张").age(18).build();valueOperations.set("user."+i,user);}}}

原生的scan用法

RedisTemplate使用Scan 

@SpringBootTest
public class AppTests_Scan {@Resource(name = "redisTemplate")private ValueOperations valueOperations;@Autowiredprivate StringRedisTemplate stringRedisTemplate;@Testvoid test1() {for (int i =1 ;i<11;i++){User user = User.builder().name(i+"号张").age(18).build();valueOperations.set("user."+i,user);}}@Testvoid test2(){//迭代扫描,指定模糊匹配,预想数量ScanOptions scanOptions = ScanOptions.scanOptions().match("user.*").count(3).build();//获取游标Cursor cursor = stringRedisTemplate.scan(scanOptions);while (cursor.hasNext()){//获取游标idSystem.out.println(cursor.getCursorId());System.out.println(cursor.next());}cursor.close();}
}

💌模拟多线程并发使用Decrby 

模拟高并发场景线上购物,多个用户(线程)同时选购某产品,提示库存信息

先初始化产品库存

@SpringBootTest
class AppTests_DecrBy {@Resource(name = "redisTemplate")private ValueOperations valueOperations;@Autowiredprivate StringRedisTemplate stringRedisTemplate;//定义一个产品private final static String productKey = "product01";@Testvoid test1() {//设置初始化库存5个valueOperations.set(productKey, 5);}
}

不考虑并发的情况下

    @Testvoid test2() throws InterruptedException {//获取线程池ExecutorService executorService = Executors.newCachedThreadPool();//模拟开启10个线程for (int i = 1; i <= 10; i++) {//开启线程执行executorService.execute(() -> {//获取库存Integer qty = valueOperations.get(productKey);//如果库存充足,产品数量就减一if (qty > 0) {qty = qty - 1;//重新设置库存valueOperations.set(productKey, qty);System.out.println(Thread.currentThread().getName() + " 库存充足");} else {System.out.println(Thread.currentThread().getName() + " 库存不足");}});}//防止主线程停止,导致模拟线程不执行Thread.sleep(60 * 1000);}

出现问题,明明库存只有5个,10个用户却都提示库存充足

考虑高并发的情况下 

使用decrement来保证原子性,解决高并发问题

    @Testvoid test3() throws InterruptedException {//获取线程池ExecutorService executorService = Executors.newCachedThreadPool();//模拟开启10个线程for (int i = 1; i <= 10; i++) {//开启线程执行executorService.execute(() -> {//获取库存Long qty = valueOperations.decrement(productKey, 1);if (qty >= 0) {System.out.println(Thread.currentThread().getName() + " 库存充足");} else {System.out.println(Thread.currentThread().getName() + " 库存不足");}});}//防止主线程停止,导致模拟线程不执行Thread.sleep(60 * 1000);}

解决了并发问题但是出现了新的问题,库存量为负数不合理(意思就是某个线程在执行删减库存时,其他线程也在同一时刻去执行,没有保障redis原子性问题)

有一种解决办法就是通过加锁synchronized来解决,但是响应能力就会大幅降低,也就失去了redis高性能的意义

所以最好的解决方式就是通过EVAL命令执行Lua脚本来解决这类问题

💌模拟多线程并发获取分布式锁SetNX

模拟某一个产品的出入库单据只能一个人(线程)操作的场景(分布式锁),当有人操作时,其他人只能等待该人操作结束之后进行操作

@SpringBootTest
@Slf4j
class AppTests_SetNx {@Resource(name = "redisTemplate")private ValueOperations valueOperations;@Autowiredprivate StringRedisTemplate stringRedisTemplate;//定义一个产品private final static String productKey = "product01";//定义锁private final static String lockKey = "lock.1";//业务private void doing(){while (true){//设置锁Boolean b = valueOperations.setIfAbsent(lockKey, 1);if(b){log.info(Thread.currentThread().getName() + " 获取到分布式锁");//业务代码开始ThreadUtil.sleep(3000);//模拟执行业务操作用时//业务代码结束stringRedisTemplate.delete(lockKey);log.info(Thread.currentThread().getName() + " 释放分布式锁");break;} else {//log.info(Thread.currentThread().getName() + " 没有获取到分布式锁,开始睡眠");ThreadUtil.sleep(2000);}}}@Testvoid test1() {//设置初始化库存5个valueOperations.set(productKey, 0);}@Testvoid test2() throws InterruptedException {//获取线程池ExecutorService executorService = Executors.newCachedThreadPool();//模拟开启10个线程for (int i = 1; i <= 10; i++) {//开启线程执行executorService.execute(this::doing);}//防止主线程停止,导致模拟线程不执行Thread.sleep(60 * 1000);}}

使用分布式锁模拟用户下单操作,防止恶意并发(一般来说用户下单产品操作时间最少也需要几秒的时间,这里预设5秒),也就是说5秒内只允许下单成功一次,也就解决了恶意并发的问题

    @Testvoid test3() throws InterruptedException {String user = "用户1";//获取线程池ExecutorService executorService = Executors.newCachedThreadPool();//模拟开启10个线程for (int i = 1; i <= 10; i++) {//开启线程执行executorService.execute(() -> {Boolean b = valueOperations.setIfAbsent("lock." + user, 1, 5, TimeUnit.SECONDS);if (b) {//下单log.info("{} 下单成功", Thread.currentThread().getName());} else {log.info("{} 稍后再试", Thread.currentThread().getName());}});}//防止主线程停止,导致模拟线程不执行Thread.sleep(60 * 1000);}

💌模拟多线程并发访问

在网关设置防止恶意并发访问,将用户ip作为key,只允许用户ip在短时间内访问2次

package com.moming;import cn.hutool.core.date.DateUtil;
import cn.hutool.core.thread.ThreadUtil;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;import javax.annotation.Resource;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;@SpringBootTest
@Slf4j
class AppTests_Increment {@Resource(name = "redisTemplate")private ValueOperations valueOperations;@Autowiredprivate StringRedisTemplate stringRedisTemplate;@Testvoid test4() throws InterruptedException {//模拟用户ipString userIp = "127.0.0.1";//获取线程池ExecutorService executorService = Executors.newCachedThreadPool();//模拟开启10个线程for (int i = 1; i <= 10; i++) {//开启线程执行executorService.execute(() -> {String seconds = DateUtil.format(DateUtil.date(), "yyyyMMddHHmmss");String key = seconds + userIp;Long count = valueOperations.increment(key, 1);if(count>2){//下单log.info("{} 超过请求次数",Thread.currentThread().getName());} else  {log.info("{} 请求正常",Thread.currentThread().getName());}});}//防止主线程停止,导致模拟线程不执行Thread.sleep(60 * 1000);}}

💌BitMap模拟在线统计 

模拟某线上活动要举办3天,参与活动的人员可以线上签到,后台通过3天人员的签到情况,统计信息

  1. 3天满勤人数: 三天都签到才算一位
  2. 3天活跃人数: 任何一天签到都算一位
@SpringBootTest
class AppTests_BitMap {@Autowiredprivate StringRedisTemplate stringRedisTemplate;@Testpublic void test2() {//2022111 20221112 20221113 三天活动//张三 1, 李四 2, 王五:3//满勤人数,1人//活跃人数,3人stringRedisTemplate.opsForValue().setBit("20221111",1,true);stringRedisTemplate.opsForValue().setBit("20221112",2,true);stringRedisTemplate.opsForValue().setBit("20221112",2,true);stringRedisTemplate.opsForValue().setBit("20221111",3,true);stringRedisTemplate.opsForValue().setBit("20221112",3,true);stringRedisTemplate.opsForValue().setBit("20221113",3,true);//RedisStringCommands.BitOperation.AND 满勤人数//RedisStringCommands.BitOperation.OR 活跃人数RedisCallback callback1 = connection -> {connection.bitOp(RedisStringCommands.BitOperation.OR,"人数统计".getBytes(StandardCharsets.UTF_8),"20221111".getBytes(StandardCharsets.UTF_8),"20221112".getBytes(StandardCharsets.UTF_8),"20221113".getBytes(StandardCharsets.UTF_8));Long count = connection.bitCount("人数统计".getBytes(StandardCharsets.UTF_8));return count;};Long count1 = stringRedisTemplate.execute(callback1);System.out.println(count1);}
}

RedisStringCommands.BitOperation.AND 满勤人数

RedisStringCommands.BitOperation.OR 活跃人数

相关内容

热门资讯

北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...