Redis day02

Redis day02

1 Redis中的数据结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HI9960v3-1630977976217)(Redis day02.assets/image-20201204114339215.png)]

传统键值存储是关联字符串值到字符串键,但是 Redis 的值不仅仅局限于简单字符串,还可以持有更复杂的数据结构。下面列的是 Redis 支持的所有数据结构,后面将逐一介绍:

  • String(字符串)
  • List(列表)
  • Set(集合)
  • Hash(哈希,键值对集合)
  • SortedSet(zset,排序集合)

1.1 String(字符串)

应用场景:粉丝数,投票数

Redis中的String,除了字符串外,还可以存:储数字以及二进制数据。

增:

127.0.0.1:6379> set name zhangsan
OK
127.0.0.1:6379> set age 18
OK
批量添加
127.0.0.1:6379> mset score 100.0 sex M
OK

删:

127.0.0.1:6379> del name
(integer) 1
127.0.0.1:6379> get name
(nil)

改:

数字自增
127.0.0.1:6379> incr age
(integer) 19
指定自增的数值
127.0.0.1:6379> incrby age 2
(integer) 21
数字自减
127.0.0.1:6379> decr age
(integer) 20
指定自减的数值
127.0.0.1:6379> decrby age 2
(integer) 18

查:

127.0.0.1:6379> get age
"18"
批量获取
127.0.0.1:6379> mget score sex
1) "100.0"
2) "M"
127.0.0.1:6379> set name zhangsan
OK
获取值的长度
127.0.0.1:6379> strlen name
(integer) 5

1.2 List(列表)

应用场景:排队。队列

增:

向mylist列表尾部添加多个数据
127.0.0.1:6379> rpush mylist xiao1hei xiao2hei xiao3hei
(integer) 3
向mylist列表头部添加多个数据
127.0.0.1:6379> lpush mylist xiao0hei xiao-1hei
(integer) 5

查:

127.0.0.1:6379> llen mylist
(integer) 5
127.0.0.1:6379> lrange mylist 0 4
1) "xiao-1hei"
2) "xiao0hei"
3) "xiao1hei"
4) "xiao2hei"
5) "xiao3hei"
查看全部,固定写法
lrange mylist 0 -1 

127.0.0.1:6379> lindex mylist 2
"xiao-1hei"

删:

127.0.0.1:6379> lpop mylist
"xiao-1hei"
127.0.0.1:6379> rpop mylist
"xiao3hei"

//lrem list count value
//从list中删除count个value,
//count=0删除全部 count>0从左开始删除 count<0从右开始删除
127.0.0.1:6379> rpush mylist xiao0hei xiao0hei xiao0hei
(integer) 6
127.0.0.1:6379> lrem mylist 3 xiao0hei
(integer) 3

改:

127.0.0.1:6379> lset mylist 0 xiaoheihei
OK
127.0.0.1:6379> lindex mylist 0
"xiaoheihei"

1.3 Set(集合)

应用场景:共同好友

增:

127.0.0.1:6379> sadd myset a b
(integer) 2
127.0.0.1:6379> sadd myset b c d
(integer) 2

查:

127.0.0.1:6379> smembers myset
1) "d"
2) "c"
3) "b"
4) "a"

删:

删除元素
127.0.0.1:6379> srem myset a
(integer) 1
127.0.0.1:6379> sismember myset a
(integer) 0

集合间的运算:

127.0.0.1:6379> sadd myset1 a b c
(integer) 3
127.0.0.1:6379> sadd myset2 b d e
(integer) 3
127.0.0.1:6379> sadd myset3 c d f
(integer) 3

myset1: a b c
myset2: b d e
myset3: c d f

获取多个集合间的差集
127.0.0.1:6379> sdiff myset1 myset2
1) "c"
2) "a"
127.0.0.1:6379> sdiff myset2 myset1
1) "d"
2) "e"
127.0.0.1:6379> sdiff myset1 myset2 myset3
1) "a"

获取多个集合间的交集
127.0.0.1:6379> sinter myset1 myset2
1) "b"
127.0.0.1:6379> sinter myset2 myset3
1) "d"
127.0.0.1:6379> sinter myset1 myset2 myset3
(empty list or set)

获取多个集合间的并集
127.0.0.1:6379> sunion myset1 myset2 myset3
1) "d"
2) "b"
3) "e"
4) "f"
5) "c"
6) "a"

1.4 Hash(键值对集合)

应用场景:存储有关联的数据,对象的另一种存放。

增:

127.0.0.1:6379> hset myhash name zhangsan
(integer) 1
127.0.0.1:6379> hmset myhash age 18 sex m
OK

不存在某个key时才添加
127.0.0.1:6379> hsetnx myhash name lisi
(integer) 0
127.0.0.1:6379> hsetnx myhash phone 18530031576
(integer) 1

查:

127.0.0.1:6379> hget myhash name
"zhangsan"
127.0.0.1:6379> hmget myhash name age sex
1) "zhangsan"
2) "18"
3) "m"

删:

127.0.0.1:6379> hdel myhash phone
(integer) 1
127.0.0.1:6379> hget myhash phone
(nil)

1.5 SortedSet(ZSet 排序集合)

应用场景:排行榜

增:

127.0.0.1:6379> zadd mysortset 18 zhaoxs 20 fanmw 22 liuyh 30 wangmj
(integer) 4

查:

获取特定元素的分数
127.0.0.1:6379> zscore mysortset zhaoxs
"18"

获取排序后指定下标范围的元素
127.0.0.1:6379> zrange mysortset 0 2
1) "zhaoxs"
2) "fanmw"
3) "lisih"

获取所有元素
127.0.0.1:6379> zrange mysortset 0 -1
1) "zhaoxs"
2) "fanmw"
3) "lisih"
4) "wangmj"

按照分数大小范围获取元素
127.0.0.1:6379> zrangebyscore mysortset 20 22
1) "fanmw"
2) "lisih"

按照分数大小范围获取元素,并进行过滤
127.0.0.1:6379> zrangebyscore mysortset 16 30
1) "zhaoxs"
2) "fanmw"
3) "lisih"
4) "wangmj"
127.0.0.1:6379> zrangebyscore mysortset 16 30 limit 2 2
1) "lisih"
2) "wangmj"

删:

127.0.0.1:6379> zrem mysortset wangmj
(integer) 1
127.0.0.1:6379> zscore mysortset wangmj
(nil)

改:

修改分数
127.0.0.1:6379> zincrby mysortset 2 zhaoxs
"20"
127.0.0.1:6379> zscore mysortset zhaoxs
"20"

注意:redis根据数据类型不同将命令分成不同的组,可以通过help命令获取帮助。

help @string

help @list

help @set

help @hash

help @sorted_set

flushdb:清除数据库里面所有的数据

2 Redis中设置key的过期时间

Redis中可以设置数据的过期时间,一旦过期自动删除数据。

  1. 设置过期时间

    127.0.0.1:6379> set name ok
    //设置10s后过期,expire单位秒
    127.0.0.1:6379> expire name 10 
    //设置10s后过期,pexpire 单位毫秒
    127.0.0.1:6379> pexpire age 10000
    (integer) 1
    
  2. 查看剩余时间

    查看剩余存活时长,单位秒
    127.0.0.1:6379> ttl name
    (integer) 7
    查看剩余存活时长,单位毫秒
    127.0.0.1:6379> pttl name
    (integer) 4006
    
  3. 取消过期

    127.0.0.1:6379> set age 18
    OK
    127.0.0.1:6379> expire age 20
    (integer) 1
    127.0.0.1:6379> ttl age
    (integer) 15
    取消过期
    127.0.0.1:6379> persist age
    (integer) 1
    ttl返回-1表示没有设置过期时间,返回-2表示数据不存在
    127.0.0.1:6379> ttl age
    (integer) -1
    127.0.0.1:6379> get age
    "18"
    

应用:手机验证码、黑名单、缓存

3 Springboot操作Redis

Spring的spring-data-redis模块中封装了RedisTemplate对象来进行对Redis的各种操作,它支持所有的Redis原生的api。提供了连接池自动管理、高度统一的Api、灵活的定制化,简化Java操作Redis的编码工作。

3.1 第1个RedisTemplate示例

  1. 导入依赖

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-pool2</artifactId>
        <version>2.9.0</version>
    </dependency>
    
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
    <!--springboot做单元测试的依赖-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
    </dependency>
    
  2. 配置

    application.yml

    spring:
      redis:
        host: 192.168.232.107
        port: 6379
        jedis:
          pool:
            max-active: 500
            max-idle: 50
            min-idle: 10
            max-wait: 30000
    
  3. 入口类:配置RedisTemplate

    @Configuration
    public class RedisConfig{
    	@Bean
        public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory){
            RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
            redisTemplate.setConnectionFactory(redisConnectionFactory);
            
            StringRedisSerializer stringRedisSerializer= new StringRedisSerializer();
           GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
            redisTemplate.setKeySerializer(stringRedisSerializer);
            redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer);
            redisTemplate.setHashKeySerializer(stringRedisSerializer);
            redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer);
            return redisTemplate;
        }
    }
    
  4. 编码

    @RuntWith(SpringRunner.class)
    @SpringBootTest(classes=RedisDay02Application.class)
    public class RedisTemplateTest{
        @Autowired
        //获取RedisTemplate工具
        private RedisTemplate<String,Object> redisTemplate;
        @Test
        public void testValueSet(){
    
            //获取操作特定数据类型的operations对象
            ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
            //通过operations对象操作数据
            valueOperations.set("name","zhangsan");
            valueOperations.set("age",18, Duration.ofSeconds(60));
        }
    
        @Test
        public void testValueGet(){
    
            ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
            Object name = valueOperations.get("name");
            Object age = valueOperations.get("age");
            System.out.println("name = " + name);
            System.out.println("age = " + age);
        }
    }
    

3.2 RedisTemplate的常用api

spring-data-redis针对jedis客户端中大量api进行了归类封装,将同一类型操作封装为operations接口。根据Redis的不同数据类型,定义了如下的operations接口:

  • ValueOperations:提供了对String类型的操作
  • ListOperations :提供了对List类型的数据操作
  • SetOperations:提供了对Set类型的数据操作
  • HashOperations:提供了对Map类型的数据操作
  • ZSetOprations:提供了对ZSet类型的数据操作
3.2.1 ValueOperations
  1. 添加:set

    ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
    valueOperations.set("name","zhangsan");//添加
    valueOperations.set("age",18, Duration.ofSeconds(60));//添加有时效的数据
    Map<String, Object> map = new HashMap<>();
    map.put("score",100.0);
    map.put("sex","男");
    valueOperations.multiSet(map);//批量添加
    
  2. 删除:delete

    redisTemplate.delete("name");
    
  3. 修改:set、increment、decremnt

    ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
    valueOperations.set("age",18);
    valueOperations.increment("age");//自增
    valueOperations.increment("age",10);//加10
    valueOperations.decrement("age");//自减
    valueOperations.decrement("age",10);//减10
    
  4. 查询:get、mget

    ValueOperations<String, Object> valueOperations = redisTemplate.opsForValue();
    Object name = valueOperations.get("name");
    Object age = valueOperations.get("age");
    System.out.println("name = " + name);
    System.out.println("age = " + age);
    
    //批量查询
    Collection<String> keys = new ArrayList<String>(0);
    keys.add("score");
    keys.add("sex");
    List<Object> values = valueOperations.multiGet(keys);
    
3.2.2 ListOperations
  1. 添加:push

    ListOperations<String, Object> listOperations = redisTemplate.opsForList();
    listOperations.leftPush("list","1");
    listOperations.leftPushAll("list","2,","3");
    
    listOperations.rightPush("list","2");
    listOperations.rightPushAll("list","3","4");
    
  2. 删除:pop

    ListOperations<String, Object> listOperations = redisTemplate.opsForList();
    Object leftPop = listOperations.leftPop("list");
    Object rightPop = listOperations.rightPop("list");
    System.out.println("leftPop = " + leftPop);
    System.out.println("rightPop = " + rightPop);
    
  3. 修改:set

    ListOperations<String, Object> listOperations = redisTemplate.opsForList();
    listOperations.set("list",1,"new value");
    
  4. 查询:index、size、range

    ListOperations<String, Object> listOperations = redisTemplate.opsForList();
    Object value = listOperations.index("list", 0);
    Long size = listOperations.size("list");
    List<Object> list = listOperations.range("list", 0, -1);
    
3.2.3 SetOperations
  1. 添加:add

    SetOperations<String, Object> setOperations = redisTemplate.opsForSet();
    setOperations.add("set", "xiao1hei", "xiao2hei");
    
  2. 删除:remove

    SetOperations<String, Object> setOperations = redisTemplate.opsForSet();
    setOperations.remove("set", "xiao1hei");
    
  3. 集合运算:difference、union、intersect

    SetOperations<String,Object> setOperations = redisTemplate.opsForSet();
    setOperations.add("set1",1,2,3,4);
    setOperations.add("set2",2,3,4,5);
    setOperations.add("set3",3,4,5,6);
    
    Set<Object> difference = setOperations.difference("set1", "set2");//set1-set2
    Collection<String> keys = new ArrayList<String>();
    keys.add("set1");
    keys.add("set2");
    keys.add("set3");
    Set<Object> union = setOperations.union(keys);//set1 + set2 + set3
    Set<Object> intersect = setOperations.intersect(keys);//求交集
    
3.2.4 HashOperations
  1. 添加:put、putAll

    HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
    hashOperations.put("map","k1","v1");
    Map<String, String> values = new HashMap<>();
    values.put("k2", "v2");
    values.put("k3", "v3");
    hashOperations.putAll("map",values);
    
  2. 删除:

    HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
    hashOperations.delete("map","k1","k2");
    
  3. 修改:

    HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
    hashOperations.put("map","age",18);
    hashOperations.increment("map","age",10);
    
  4. 查询:

    HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
    Object v1 = hashOperations.get("map", "k1");
    Collection<String> keys = new ArrayList<>();
    keys.add("k2");
    keys.add("k3");
    List<Object> values = hashOperations.multiGet("map", keys);
    Boolean hasKey = hashOperations.hasKey("map", "k1");
    Long size = hashOperations.size("map");
    
3.2.5 ZSetOperations
  1. 添加:

    ZSetOperations<String, Object> zSetOperations = redisTemplate.opsForZSet();
    zSetOperations.add("zset","zhangsan",100);
    zSetOperations.add("zset","lisi",60);
    
  2. 删除:

    zSetOperations.remove("zset","zhangsan","lisi");
    zSetOperations.removeRange("zset",0,2);
    zSetOperations.removeRangeByScore("zset",50,99.0);
    
  3. 修改:

    zSetOperations.incrementScore("zset", "lisi", 10.0);
    
  4. 查询:

    Set<Object> zset1 = zSetOperations.range("zset", 0, -1);
    Set<Object> zset2 = zSetOperations.rangeByScore("zset", 40, 100);
    
     Set<ZSetOperations.TypedTuple<Object>> scores = zSetOperations.rangeWithScores("zset", 0, -1);
    for (ZSetOperations.TypedTuple e:scores) {
        System.out.println(e.getValue()+" "+e.getScore());
    }
    
    Set<ZSetOperations.TypedTuple<Object>> scores2 = zSetOperations.rangeByScoreWithScores("zset", 40, 100);
    for (ZSetOperations.TypedTuple e:scores2) {
        System.out.println(e.getValue()+" "+e.getScore());
    } 
    

4 Redis缓存

4.1 Redis缓存引言

缓存:对于数据库中的热点数据的备份,便于访问,提高应用性能。

单机架构的缓存方案

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GErIY3j8-1630977976219)(Redis day02.assets/image-20201107230421208.png)]

EhCache直接将数据缓存在JVM中,速度快,效率高。但是在分布式集群环境下,缓存管理非常麻烦,比如:当修改了一条数据后,必须通知到缓存了该数据的所有缓存。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I14oH8UE-1630977976220)(Redis day02.assets/image-20201107231737082.png)]

解决方案:Redis缓存

Redis基于内存操作,性能远超关系型数据库,可以代替EhCache充当缓存。单独部署Redis服务,应用通过网络和Redis通信,虽效率略低于EhCache,但处理集群分布式缓存有成熟的方案。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SRgMdBH1-1630977976221)(Redis day02.assets/image-20201107232452489.png)]

4.2 Redis缓存的使用

Redis缓存的设计思路:

  • 在执行查询时,先查询redis缓存,如果有数据则不在调用dao直接返回;如果查不到,才调用dao,并将数据保存到缓存
  • 在执行增删改后,需要清空缓存,避免脏数据

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tkE95i1L-1630977976222)(Redis day02.assets/image-20201108102214591.png)]

为避免操作缓存的代码和原始业务代码耦合,不能将操作缓存的代码硬编码到业务方法中。可以将操作Redis缓存的代码定义成Advice(增强),使用AOP的方式动态增强。

4.2.1实战中Spring Boot的Redis缓存配置

事实上,在Springboot中配置缓存无需手写增强类,Springboot对缓存的AOP方式进行了抽取封装,内置了一套开箱即用的缓存机制。

**注解:**Spring内置了缓存注解

  • Cacheable:用在方法上,执行方法前先查询缓存,如果缓存有数据,直接返回;如果缓存中没有数据,则执行查询方法,并将结果保存到缓存中
  • CacheEvict:用在方法上,可以在方法执行前或后删除缓存

增强类: Spring内置了RedisCacheManager缓存增强类

具体步骤:

  1. 引入依赖。

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
        <version>2.1.4.RELEASE</version>
    </dependency>
    
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-pool2</artifactId>
        <version>2.9.0</version>
    </dependency>
    
  2. 在目标方法上面使用缓存。

    @CacheEvict(value="NewsServiceImpl",allEntries = true,beforeInvocation = true)
    @Cacheable(value="NewsServiceImpl",key="#root.methodName+#id")
    
  3. 在Application启动类上面添加开启缓存注解。

    @EnableCaching//开启缓存
    public class Application {}
    
  4. 在配置类中对redis连接进行管理。

     //配置缓存管理器
        @Bean
        public CacheManager cacheManager(RedisConnectionFactory connectionFactory){
    
            RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory);
    
            return new RedisCacheManager(redisCacheWriter,getRedisCacheConfiguration(20),
                    getRedisCacheConfigurationMap());
        }
    
        private Map<String, RedisCacheConfiguration> getRedisCacheConfigurationMap(){
            Map<String, RedisCacheConfiguration> redisCacheConfigurationMap = new HashMap<>();
            //以NewsServiceImpl开头的缓存要存储100秒
            redisCacheConfigurationMap.put("NewsServiceImpl", getRedisCacheConfiguration(100));
            return redisCacheConfigurationMap;
        }
        //RedisCacheConfiguration 用于负责Redis的缓存配置
        private RedisCacheConfiguration getRedisCacheConfiguration(int seconds){
            RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
            GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
            return redisCacheConfiguration
                    .serializeValuesWith(
                            RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer)
                    )
                    .entryTtl(Duration.ofSeconds(seconds));
        }
    
  5. 在application.yml中对redis服务器进行配置。

    spring:
      redis:
        lettuce:
          pool:
            max-active: 500
            max-idle: 50
            min-idle: 10
            max-wait: 30000
        host: 192.168.232.107
        port: 6379
    

tRedisCacheConfiguration(int seconds){
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
return redisCacheConfiguration
.serializeValuesWith(
RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer)
)
.entryTtl(Duration.ofSeconds(seconds));
}




5. 在application.yml中对redis服务器进行配置。

```yml
spring:
  redis:
    lettuce:
      pool:
        max-active: 500
        max-idle: 50
        min-idle: 10
        max-wait: 30000
    host: 192.168.232.107
    port: 6379
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值