文章目录
Redis
1 其他命令
1.1 Redis事务
可以让用户在不被打断的情况下对多个键执行操作:watch、multi、exec、unwatch、discard
概念:
Redis的基本事务需要用到multi命令和exec命令,这种事务可以让一个客户端在不被其他客户端打断的情况下执行多个命令,和关系数据库那种可以执行的过程中进行回滚的事务不同,在redis里面,被multi和exec包围的所有命令会一个接一个的执行,直到所有的命令执行完毕为止。当一个事务执行完毕之后,redis才会处理其他客户端的命令。
编译错误,回滚,运行时错误不会。造成的情况不一样。
watch处理事务并发
1.2 key过期时间
在使用 Redis 存储数据的时候,有些数据可能在某个时间点之后就不再有用了,用户可以使用 DEL 命令显式地删除这些无用数据,也可以通过 Redis 的过期时间(expiration)特性来让一个键在给定的时限(timeout)之后自动被删除。当我们说一个键“带有生存时间(timetolive)”或者一个键“会在特定时间之后过期(expire)”时,我们指的是 Redis 会在这个键的过期时间到达时自动删除该键。
注意:实际开发中,过期时间慎用
1.3 其他
- 返回值类型:type keyName
- keys:返回满足给定pattern的所有key(* 通配N个字符,?统配1个字符,[]代表指定字符占位)
例如:keys [012] 代表出现0/1/2的内容,并且此方式可以查询key中存在 * 或?的内容,比如user*?name这样的key - dbsize:查看仓库中存在的key总共多少个
- exists:确认一个key是否存在
- rename:重命名key
2 SpringBoot集成redis
- 加入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
- 配置:application.yml
spring:
redis:
databases: 0
timeout: 3000ms
host: xxx.xxx.xxx.xxx
port: 6379
password: 123
jedis:
pool:
max-idle: 200 # 最大空闲连接数
min-idle: 200
max-active: 2000
max-wait: 1000ms
- 测试
类型String、List、Hash、Set、ZSet对应的方法分别是opsForValue()、opsForList()、opsForHash()、opsForSet()、opsForZSet()
springBoot 集成 Redis 出现的: Unable to connect to Redis 问题
2.1 处理对象的模板
默认的 StringRedisTemplate 只能处理 String,但是我们在实际场景中可能直接存储对象,就需要对象模板:objectRedisTemplate
这个需要我们自己来定义,定义方式可以参考 StringRedisTemplate 来处理
2.2 处理json模板
处理json数据的模板是对象模板的稍作修改:
3 Redis分页
案例:
4 RedisAtomicInteger和RedisAtomicLong
高并发增量计数器,并且保证每一个线程的安全性,提供原子性能操作,通过线程安全的方式操作加减。
常见场景:
1.监控每一个功能被使用的次数,如果多用户并发访问时,为了保证数据真实有效,则使用这两个类来处理,两个类之间的唯一区别是值得范围的大小,Long的范围大于Integer。
2.秒杀计数器
两个类的操作几乎一致,区别是自增时返回的类型不同:
java中的AtomicInteger不适用于分布式,单体应用,AtomicLong只能在一个应用中使用
RedisAtomicLong可以在所有与Redis有连接的应用中使用
5 秒杀简单控制器
感受单体应用:
秒杀控制器:
@RestController
public class MsController {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@PostMapping("ms/goods")
public JsonResult ms(String name) {
if(name == null || name.isEmpty()) {
return new JsonResult(1001,"数据不正确");
}
// 秒杀计数器
RedisAtomicInteger msCount = new RedisAtomicInteger("ms_count",stringRedisTemplate.getConnectionFactory());
int count = msCount.incrementAndGet();
if(count > 5) {
return new JsonResult(200,"对不起,你没抢到");
}
// 通过了,进入秒杀队列
stringRedisTemplate.opsForList().leftPush("ms_queue",name);
return new JsonResult(200,"秒杀成功",count);
}
}
写一个定时器,1s消费一个
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Scheduled(fixedRate = 1000)
public void taskMs() {
// 消费队列 每次取一个
String name = stringRedisTemplate.opsForList().rightPop("ms_queue");
// 写入业务数据库
if(name != null) {
System.out.println("恭喜:"+name+"秒杀商品成功!");
}
}