本文已参与「新人创作礼」活动,一起开启掘金创作之路。
前言
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可以实现的场景就越多啦~~~