Redis介绍
Redis基于内存的key-value结构的NOSQL(非关系型)数据库
非关系型数据库:表与表之间没有复杂的关系
Redis的优点
- 基于内存存储,读写性能高 – Redis读的速度是110000次/S
- 适合存储热点数据(商品、新闻资讯)
- 它存储的value类型比较丰富,也称为结构化NoSQL数据库
Redis的缺点
Redis的安装
直接解压windows版压缩包就可以
启动:
①双击启动 无密码的形式
redis-server.exe
②cmd命令行启动
redis-server.exe redis.windows.conf
前提是修改了配置文件
在配置文件中搜索 ctrl + f
foobared
将注释 # 去掉 , 将 foobared 替换为 你的密码即可
Redis的连接
①双击启动 无密码的形式
redis-cli.exe
②cmd命令行启动
redis-cli.exe -a 你的密码
或远程连接
redis-cli.exe -h 192.168.166.60 -p 6379 -a 你的密码
验证登录
使用 ping 返回 pang 为成功
192.168.166.60:6379> ping
PONG
Redis的使用
更多命令可以参考Redis中文网:https://www.redis.net.cn
Redis中的数据类型
key 数据类型为 String
Value的数据类型有5种
① String *常用
② Hash *常用
③ List 有序
④ Set 无序
⑤ ZSet 有序
String的使用
get set
192.168.166.60:6379> set name zs
OK
192.168.166.60:6379> get name
"zs"
192.168.166.60:6379>
重复set会覆盖
setex(expire)ttl
192.168.166.60:6379> setex age 10 18
OK
192.168.166.60:6379> get age
"18"
192.168.166.60:6379> ttl age
(integer) -2
192.168.166.60:6379> setex age 10 18 //10 秒过期
OK
192.168.166.60:6379> ttl age
(integer) 8
192.168.166.60:6379> ttl age
(integer) 6
192.168.166.60:6379> get age
"18"
192.168.166.60:6379> ttl age
(integer) -2
192.168.166.60:6379> get age
(nil)
192.168.166.60:6379>
过期是-2
永久是-1
正数是倒计时过期时间
setnx(not exit)
分布式锁(应用场景)
不能覆盖value
192.168.166.60:6379> setnx sex female
(integer) 1
192.168.166.60:6379> setnx sex male
(integer) 0
192.168.166.60:6379> get sex
"female"
192.168.166.60:6379>
Hash
Hash类型极其类似于java中的Map,值里面可以存放一组组的键值对
该类型非常适合于存储java中对象的信息
192.168.166.60:6379> hset user1 name zs
(integer) 1
192.168.166.60:6379> hset user1 age 18
(integer) 1
192.168.166.60:6379> hgetall user1
1) "name"
2) "zs"
3) "age"
4) "18"
192.168.166.60:6379> hkeys user1
1) "name"
2) "age"
192.168.166.60:6379> hvals user1
1) "zs"
2) "18"
192.168.166.60:6379> hdel user1 name [可以删除多个字段 空格 隔开]
(integer) 1
192.168.166.60:6379> hkeys user1
1) "age"
192.168.166.60:6379> hvals user1
1) "18"
List列表(队列)
List类型底层是一个双向字符串链表。里面的元素是有序的,可重复的
我们可以从链表的任何一端进行元素的增删
* 新增
左压入
lpush key value1 value2 ...
右压入
rpush key value1 value2 ...
* 查询元素(闭合区间)
lrange key 开始索引 结束索引
* 列表长度
llen key
* 删除元素
左弹出
lpop key
右弹出
rpop key
Set集合
Set类型底层是一张hash表。里面的元素是无序的,不可重复的
* 新增
sadd key value1 value2 ...
* 查询元素
smembers key
* 查询集合数量
scard key
* 删除元素
srem key value1 value2 ...
* 求集合的交集:
sinter key1 key2
* 求集合的并集:
sunion key1 key2
* 求集合的差集:
sdiff key1 key2
ZSet集合
Zset,也称sortedSet, 在Set的基础上,加入了有序功能,在添加元素的时候,允许指定一个分数,它会按照这个分数排序
* 新增
zadd key score1 value1 score2 value2 ...
* 查询
升序
zrange key start end [withscores]
降序
zrevrange key start end [withscores]
* 加分
zincrby key increment member
* 删除
zrem key value
Redis 通用命令
192.168.166.60:6379> exists sex
(integer) 1
192.168.166.60:6379> get sex
"female"
192.168.166.60:6379> keys *
1) "sex"
2) "name"
3) "user1"
192.168.166.60:6379> type sex
string
192.168.166.60:6379> type name
string
192.168.166.60:6379> type user1
hash
192.168.166.60:6379> select 1
OK
192.168.166.60:6379[1]> select 0
OK
192.168.166.60:6379> select 1
OK
192.168.166.60:6379[1]> type name
none
192.168.166.60:6379[1]> keys *
(empty list or set)
192.168.166.60:6379[1]> select 0
OK
192.168.166.60:6379> keys *
1) "sex"
2) "name"
3) "user1"
192.168.166.60:6379>
Redis图形客户端
在我的资源中有Redis-DeskTop软件,解压安装即可使用
Redis在Java中的使用
Spring 对 Redis 客户端进行了整合,提供了 Spring Data Redis,在Spring Boot项目中还提供了对应的Starter,即 spring-boot-starter-data-redis。
RedisTemplate
- ValueOperations:简单的键值对数据操作
- SetOperations:set类型数据操作
- ZSetOperations:zset类型数据操作
- HashOperations:hash类型的数据操作
- ListOperations:list类型的数据操作
导入坐标
在sky-server模块导入spring data redis依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
添加redis配置
application-dev.yml
sky:
redis:
host: localhost
port: 6379
password: itheima
application.yml
spring:
redis:
host: ${sky.redis.host}
port: ${sky.redis.port}
password: ${sky.redis.password}
RedisTemplate测试类
@SpringBootTest
public class RedisTest {
@Autowired
private RedisTemplate redisTemplate;
// 获取五种操作类型的对象
@Test
public void test()throws Exception{
// 1.字符串类型
ValueOperations valueOperations = redisTemplate.opsForValue();
// 2.哈希类型
HashOperations hashOperations = redisTemplate.opsForHash();
// 3.列表类型
ListOperations listOperations = redisTemplate.opsForList();
// 4.集合类型
SetOperations setOperations = redisTemplate.opsForSet();
// 5.有序集合类型
ZSetOperations zSetOperations = redisTemplate.opsForZSet();
}
}
API
操作字符串类型数据
// 字符串类型
@Test
public void test02()throws Exception{
// 1.字符串操作对象
ValueOperations valueOperations = redisTemplate.opsForValue();
// 存
// valueOperations.set("mystr","i am a string");
// 取
// System.out.println(valueOperations.get("mystr"));
// 存短信验证码,5分钟有效时间
// valueOperations.set("sms:13500135001","223355", Duration.ofSeconds(300));
//存一个java对象(要求实现序列化接口)
Category category = Category.builder()
.name("烤鱼套餐")
.status(1)
.createTime(LocalDateTime.now())
.build();
// valueOperations.set("category",category);
// 查询java对象
System.out.println(valueOperations.get("category"));
}
操作哈希类型数据
// 哈希类型
@Test
public void test03()throws Exception{
// 2.哈希操作对象
HashOperations hashOperations = redisTemplate.opsForHash();
// 存
hashOperations.put("user:1","name","饭岛爱");
hashOperations.put("user:1","age",18);
// 取一个
System.out.println(hashOperations.get("user:1", "age"));
System.out.println("--------------------------");
// 取出所有元素
Set hkeys = hashOperations.keys("user:1");
hkeys.forEach(hkey->{
System.out.println(hashOperations.get("user:1", hkey));
});
// 删除
hashOperations.delete("user:1","age");
}
操作列表类型数据
// 列表类型
@Test
public void test04()throws Exception{
// 3.列表操作对象
ListOperations listOperations = redisTemplate.opsForList();
// 左压入
listOperations.leftPushAll("mylist","a","b","c");
// 查询 c b a
List mylist = listOperations.range("mylist", 0, -1);
System.out.println(mylist);
// 右弹出
System.out.println(listOperations.rightPop("mylist"));
// 查询 c b
List mylist1 = listOperations.range("mylist", 0, -1);
System.out.println(mylist1);
}
操作集合类型数据
// 集合类型
@Test
public void test05()throws Exception{
// 4.集合操作对象
SetOperations setOperations = redisTemplate.opsForSet();
// 存
// setOperations.add("tom","唱","跳","rap","打篮球");
// 存
// setOperations.add("jack","爱坤","唱","rap");
// 查询
Set set = setOperations.members("jack");
System.out.println(set);
// 交集
System.out.println(setOperations.intersect("tom", "jack"));
// 并集
System.out.println(setOperations.union("tom", "jack"));
// 删除
setOperations.remove("tom","rap");
}
操作有序集合类型数据
// 有序集合类型
@Test
public void test06()throws Exception{
// 5.有序集合操作对象
ZSetOperations zSetOperations = redisTemplate.opsForZSet();
// 存
// zSetOperations.add("java","tom",66.4);
// zSetOperations.add("java","jack",45.2);
// zSetOperations.add("java","飞机",23.2);
// 苦练安其拉
zSetOperations.incrementScore("java","tom",30);
// 查询 降序
System.out.println(zSetOperations.reverseRange("java", 0, -1));
}
通用操作
// 通用操作
@Test
public void test07()throws Exception{
// 查询 keys c*
Set keys = redisTemplate.keys("c*");
System.out.println(keys);
// 批量删除
redisTemplate.delete(keys);
// 判断key是否存在
System.out.println(redisTemplate.hasKey("tom"));
}
统一处理时间格式配置类
主要是为了方便使用图像化客户端进行对redis中存储数据的查看和对日期格式的处理(不是必须的)
package com.sky.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
// Redis配置类
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
@Bean
@SuppressWarnings("all")
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
//原生RedisTemplate
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(factory);
//json序列化
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = getJackson2JsonRedisSerializer();
// -------- 设置key value 序列化方式 --------
// key采用String的序列化方式
template.setKeySerializer(RedisSerializer.string());
// hash的key也采用String的序列化方式
template.setHashKeySerializer(RedisSerializer.string());
// value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
private Jackson2JsonRedisSerializer getJackson2JsonRedisSerializer() {
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
//设置ObjectMapper访问权限
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
//记录序列化之后的数据类型,方便反序列化
om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,
ObjectMapper.DefaultTyping.NON_FINAL);
//LocalDatetime序列化,默认不兼容jdk8日期序列化
JavaTimeModule timeModule = new JavaTimeModule();
timeModule.addDeserializer(LocalDate.class,
new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
timeModule.addDeserializer(LocalDateTime.class,
new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
timeModule.addSerializer(LocalDate.class,
new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
timeModule.addSerializer(LocalDateTime.class,
new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
//关闭默认的日期格式化方式,默认UTC日期格式 yyyy-MM-dd’T’HH:mm:ss.SSS
om.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
om.registerModule(timeModule);
jackson2JsonRedisSerializer.setObjectMapper(om);
return jackson2JsonRedisSerializer;
}
}
在项目中的应用
ShopController设置状态
@RestController
@RequestMapping("/admin/shop")
public class ShopController {
@Autowired
private RedisTemplate redisTemplate;
// 设置店铺状态
@PutMapping("/{status}")
public Result setStatus(@PathVariable("status") Integer status) {
// 调用redis设置
ValueOperations valueOperations = redisTemplate.opsForValue();
valueOperations.set("SHOP_STATUS", status);
return Result.success();
}
}
用户端查询营业状态
// 店铺管理
@RestController
@RequestMapping("/user/shop")
public class AppShopController {
@Autowired
private RedisTemplate redisTemplate;
// 查询店铺状态
@GetMapping("/status")
public Result getShopStatus(){
Integer status = (Integer) redisTemplate.opsForValue().get("SHOP_STATUS");
return Result.success(status);
}
}
管理端查询营业状态
// 获取店铺的营业状态
@GetMapping("/status")
public Result getStatus(){
Integer status = (Integer) redisTemplate.opsForValue().get("SHOP_STATUS");
return Result.success(status);
}
菜品缓存
读取数据的时候:
- 先判断缓存中有无数据,
- 若有直接返回
- 若无,再查询mysql,将数据放入redis中一份,最后返回
写数据的时候:文章来源:https://www.toymoban.com/news/detail-671695.html
- 保证redis和mysql中数据一致.一旦有写操作的时候,删除缓存中数据
redis数据存储设计
首先明确在redis中存储的数据格式,必须确定的是key部分要包含查询条件文章来源地址https://www.toymoban.com/news/detail-671695.html
redis缓存的key(DISH:分类的id) | redis缓存的value |
---|---|
DISH:1 | List<DishVo>的json |
缓存菜品数据
@RestController
@RequestMapping("/user/dish")
@Slf4j
public class AppDishController {
@Autowired
private DishService dishService;
@Autowired
private RedisTemplate redisTemplate;
// 根据分类id查询菜品列表(小程序段)
@GetMapping("/list")
public Result getList(@RequestParam Long categoryId) {
List<DishVO> voList = null;
// ---------------------start
// 先查询redis中是否有该分类的菜品缓存
String dishKey = "DISH:" + categoryId;
if (redisTemplate.hasKey(dishKey)) {
log.info("查询缓存...");
voList = (List<DishVO>) redisTemplate.opsForValue().get(dishKey);
return Result.success(voList);
}
// ---------------------end
// 封装dto条件
DishPageDTO dishPageDTO = DishPageDTO.builder()
.categoryId(categoryId)
.status(1)
.build();
// 调用service查询,返回结果
log.info("查询数据库...");
voList = dishService.getParamList(dishPageDTO);
// -------------------------- start
// 将数据库数据同步到缓存
redisTemplate.opsForValue().set(dishKey, voList);
// -------------------------- end
return Result.success(voList);
}
}
缓存一致性(了解什么是延迟双删)
@Autowired
private RedisTemplate redisTemplate;
// 菜品新增
@PostMapping
public Result saveDishWithFlavor(@RequestBody DishDTO dishDTO) {
dishService.saveDishWithFlavor(dishDTO);
// 清理缓存
redisTemplate.delete("DISH:"+dishDTO.getCategoryId());
return Result.success();
}
// 修改菜品
@PutMapping
public Result updateById(@RequestBody DishDTO dishDTO) {
dishService.updateById(dishDTO);
// 清理缓存
Set dishKey = redisTemplate.keys("DISH*");
redisTemplate.delete(dishKey);
return Result.success();
}
// 删除菜品
@DeleteMapping
public Result deleteBatch(@RequestParam List<Long> ids) {
dishService.deleteBatch(ids);
// 清理缓存
Set dishKey = redisTemplate.keys("DISH*");
redisTemplate.delete(dishKey);
return Result.success();
}
// 启用禁用
@PostMapping("/status/{status}")
public Result startOrStop(
@PathVariable("status") Integer status,
@RequestParam Long id) {
dishService.startOrStop(status, id);
// 清理缓存
Set dishKey = redisTemplate.keys("DISH*");
redisTemplate.delete(dishKey);
return Result.success();
}
到了这里,关于Redis基于内存的key-value结构化NOSQL(非关系型)数据库的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!