Redis的string数据结构各场景项目实战

140 阅读3分钟

​本文已参与「新人创作礼」活动,一起开启掘金创作之路。

前言

Redis常用数据结构:String、List、Hash、Set、Zset。根据数据结构的特点可实现的场景就会多样。所谓这五种数据结构,是key-value存储格式下value中的数据结构为五种。篇幅有限,本文主要对string类型举例~

注:Redis查看命令: help @xx 例如查看操作string类型的命令:help @String 如图

注:zset的查看命令特殊 是 help @sorted_set

本文示例环境

  • springboot项目,引入redis。(具体情况具体介绍)
  • java使用redisson作为客户端
  • 使用到的工具有:nginx,jmeter,ApiPost/PostMan

String类型的使用场景

string-缓存场景:session缓存

0、场景介绍:

拿用户登陆举例:post请求提交了用户名密码,将两者存入session中。即使在分布式环境中,session信息也可以共享。

1、环境:

  • 使用spring session与redis的整合,pom引入依赖
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <version>2.1.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-data-redis</artifactId>
            <version>2.6.1</version>
        </dependency>

2、配置: 

#指定默认session缓存方式
spring:
  redis:
    host: xx.xx.130.130
    port: 6379
    password: 123456
  session:
    store-type: redis

3、 java代码:

@SpringBootApplication
@EnableRedisHttpSession
public class RedisDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(RedisDemoApplication.class, args);
    }

}
@RestController
@RequestMapping("/session")
public class SessionController {
    @PostMapping
    public String setSession(HttpSession session,String name,String password){
        session.setAttribute("name",name);
        session.setAttribute("password",password);
        return "ok";
    }
}

string-缓存场景:单值/对象缓存

0、场景介绍

上个案例中spring session 和redis将用户信息存储,登陆业务中,如果查询有此用户,密码正确,准许登入后,用户的信息经常使用,例如用户的部门信息要拿去做权限等,不妨将用户(这个java对象)缓存在redis中。

1、环境:

  • 使用redisson作为客户端,pom引入依赖
  • 使用阿里巴巴的fastjson序列化对象为json字符串存入redis
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.78</version>
        </dependency>
        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.16.6</version>
        </dependency>
        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson-spring-boot-starter</artifactId>
            <version>3.16.7</version>
        </dependency>

2、配置:

和上个例子一样的yml配置文件,没有变。但是要添加一个redisson的配置类

@Configuration
public class RedissonConfig {

    @Value("${spring.redis.host}")
    private String host;
    @Value("${spring.redis.port}")
    private String port;
    @Value("${spring.redis.password}")
    private String password;

    /**
     * 配置单节点模式
     *
     * @return redisson实例
     */
    @Bean
    public RedissonClient redissonClient() {
        Config config = new Config();
        config.useSingleServer().setAddress("redis://" + host + ":" + port).setPassword(password);
        return Redisson.create(config);
    }
}

3、java代码:

1)还是上个例子中:多了创建用户对象UserInfo后调用方法缓存用户对象

@RestController
@RequestMapping("/session")
public class SessionController {
    @Autowired
    private CacheService cacheService;
    @PostMapping
    public String setSession(HttpSession session, String name, String password){
        session.setAttribute("name",name);
        session.setAttribute("password",password);
        //---------创建对象
        UserInfo userInfo = new UserInfo(name,password);
        //---------用redis缓存对象
        cacheService.cacheUser(userInfo);
        return "ok";
    }
}

2)redisson缓存对象

@Service
public class CacheService {
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    public void cacheUser(UserInfo userInfo){
        //将java对象转为json 字符串
        String userJSONString = JSON.toJSONString(userInfo);
        //操作redisson 的 API,相当于redis命令:set userInfo ...
        stringRedisTemplate.opsForValue().set("userInfo", userJSONString);
    }
}

string-分布式锁场景:

0、场景介绍

传说中的互联网秒杀场景:简例:

  • 20个商品库存存在redis中,2台服务器(本地伪分布式,同一服务起个8099端口,再起一个8088端口,使用nginx负载均衡(将请求打到不同机器上))接收200请求(jmeter发送),要保证不多扣不少扣库存。
  • 使用redis分布式锁,保证两台机器各自接受的多请求中,同一时刻只有一个请求执行扣减库存,保证数据安全。

1、环境:

  • nginx:本次举例使用nginx version: nginx/1.21.0
  • jmeter:本次举例使用5.4版本

2、配置:

  • redis环境与前述环境一样:

    • 提前向redis存库存数量20个:即set stock 20
  • nginx配置(只展示重点部分:upstream + location里):

http {
    #服务器集群,并起个名字redisdemo
    upstream redisdemo {
        server 127.0.0.1:8099;
        server 127.0.0.1:8088;
	}
    #gzip  on;
 
    server {
        listen       8080;
        server_name  localhost;
 
        location / {
            #这里的名字和上面配置的对上redisdemo
			proxy_pass http://redisdemo;
			proxy_redirect default;
        }
    }
}

  • 项目用两个端口分别启动  

  • jmeter配置:

    • 200个线程,3秒跑完,循环一次(图一)
    • 配置请求地址(nginx代理地址localhost:8080)+接口名(/deduct_stock)(图二)

3、java代码:

        扣减库存的接口代码:

@RestController
public class RedisLockController {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private RedissonClient redissonClient;

    @RequestMapping("/deduct_stock")
    public String deductStock(){
        //给锁起个名字
        String lockKey = "product_stock";
        //获取锁对象
        RLock redissonLock = redissonClient.getLock(lockKey);
        try {
            redissonLock.lock();
            //获取库存
            int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));
            //库存充足
            if (stock > 0) {
                //扣减库存
                int realStock = stock - 1;
                //实际库存存入redis
                stringRedisTemplate.opsForValue().set("stock", realStock + "");
                System.out.println("扣减成功,剩余库存:" + realStock);
            } else {
                System.out.println("扣减失败,库存不足");
            }
        } finally {
            //释放锁
            redissonLock.unlock();
        }
        return "ok";
    }
}

string-计数器场景:

 0、场景介绍

比如某个直播间/文章,有多少人进入/查看,可以用redis实现计数器的功能:

1、环境

  • 与前面环境一致没有变动
  • jmeter新建任务3s200请求模拟访问阅读大v博主的文章

2、配置:

  • 与上述配置不变:仍使用nginx代理两台服务器

3、java代码

@RestController
public class CounterController {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @RequestMapping("/counter")
    public String counter(){
        //谁的文章
        String userName = "大V博主";
        //哪篇文章
        String articleName = "论xxxxxx";
        Long increment = stringRedisTemplate.opsForValue().increment(userName+":"+articleName+":"+"how-many");
        return "ok";
    }
}

总结

        先写到这里呀~欢迎补充,想到其它案例再来补充! 其实无非就是API的操作,场景很多样,对redis的存储数据结构和命令了解更多,用redis可以实现的场景就越多啦~~~