非关系型数据库Redis(一):Redis命令与如何实现二级缓存和分布式Session

前言:本文为原创 若有错误欢迎评论!

一.Redis的数据结构

1.String:

  1. set/get(基本操作)

set key value
get key

  1. mset(一次存入多个)

mset key1 value1 key2 value2

  1. mget(一次取出多个)

mget key1 key2 key3

  1. incr(每次value必须是数字 等同i++)(是原子性的 线程安全的 可以搭配lua脚本保证完全一起执行)

incr key

  1. incrby(每次增加指定的值)

incrby key incrNum

  1. decr(每次value必须是数字 相当i–)(是原子性的 线程安全的 可以搭配lua脚本保证完全一起执行)

decr key

  1. decrby(每次减少指定的值)

decr key decrNum

  1. setnx(如果不存在这个key就存入 返回值为 1:成功,0:失败)

setnx key value

  1. msetnx(存入多个 如果不存在就存入)

mset key1 value1 key2 value2

  1. setex(给key可以设置过期时间 单位是秒)

setex age second value

  1. getset(存入新值并返回旧值)

getset key value

  1. getrange(获取字符串value的指定长度 相当于字符串函数substr)

getrange key startpos lenth

  1. append(给指定的key拼接字符串 返回长度)

append key value

2.Hash:

  • Hash的数据结构:Map<String,Map<String,String>> (即一个key对应多个filed 一个filed对应一个key)
  1. hset/hget(基本操作)

hset key filed1 value
hset key filed2 value
hget key filed

  1. hgetall(打印key对应的所有value)

hgetall key

  1. hmset(一次放入多个)

hmset key1 filed1 value1 key2 filled 2 value2

  1. hmget(一次取多个filed多赢的值)

hmget key1 filed1 key2 filed2

  1. hlen(一个key对应了多少对filed)

hlen key

  1. hdel(删除一个filed)

hdel key filed

3.List

  1. lpush(从第一个值开始压栈 是栈结构 先进后出)

lpush key value1 value2

  1. lrang(取指定下标的值 0 -1 表示取全部)

lrange key 0 -1
lrange key startpos num

  1. lpop(抛出栈顶(即最后一个存入的)并返回该值)

lpop key

  1. rpush(将值压入栈底)

rpush key value

  1. rpop(抛出栈底的值)

rpop key

  1. llen(list的长度)

llen key

  1. lindex(只获取key第num个元素)

lindex key num

  1. lrem(删除第num个元素)

lrem key num

4.Set

  • 底层是HashMap 一个key对应的多个value没有重复的
  1. sadd(添加)

sadd key value1 value2 value3

  1. smembers(取全部的值)

smembers key

  1. spop(随机抛出一个元素 并返回该值)

spop key

  1. sdiff(获得前面set不存在于后面set的元素)

sdiff set1 set2

  1. sunion(获得两个set的并集)

sunion set1 set2

  1. sinter(获得两个set的交集)

sinter set1 set2

5.SortSet

  • 对set的基础进行score,再根据score进行排序
  1. zadd(添加)

zadd key socer1 obj1 socer2 obj2

  1. zrange(递增排序,即由小到大排序后,取 [start 下标 , stop 下标]所有元素 )

zrange key 0 -1 # 说明,-1 代表取全部元素
zrange key start stop [withscores] # 说明,withscores 代表是否显示分数

  1. zrevrang (递减排序,即由大到小排序后,取 [start 下标 , stop 下标]所有元素 )

zrevrang key start stop [WITHSCORES]

  1. zrangebyscore(通过score获得在一个范围内的obj)

zrangebyscore key min max

  1. zrank(获得指定 obj 的排名 从小到大的顺序 最小值返回的排名是0)

zrank key obj

  1. zrevrank(获得指定 obj 的排名 从大到小的顺序 最小值返回的排名是0)

zrevrank key obj

  1. zcard(查看有多少个元素)

zcard key

  1. zsocer(获得 obj 的分数)

zsocre key obj

  1. zrem(删除对应obj 的值)

zrem key obj

二.Redis其他命令

1.消息发布订阅

  1. PUBLISH(将消息发送到指定的channel 并返回客户端数量)

PUBLISH channelName message

  1. SUBSCRIBE(订阅指定的channel的消息)

SUBSCRIBE channelName

  1. UNSUBSCRIBE(取消订阅 如果不指定channel 则取消全部订阅)

UNSUBSCRIBE channelName

2.Redis事务

  1. MULTI(开启事务 之后每执行一个命令都放进队列并返回QUENE)

MULTI

  1. EXEC(执行所有命令 并返回队列中任务的执行结果)

EXEC

  1. DISCARD(清空队列中所有任务)

DISCARD

  1. WATCH(在MULIT开启事务之前使用 如果多端口修改了被WATCH的值 则事务提交失败)

WATCH key

三.SpringBoot整和redis

1.依赖

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>

2.在根目录新建RedisConfig.java 并注解【@Configuration】

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory){
        RedisTemplate<String, String> redisTemplate = new RedisTemplate<String,String>();
        redisTemplate.setConnectionFactory(factory);
        
        /**
         * 定义好三种序列化方式:Jackson序列化、Jdk序列化、String序列化
         */
       
        /**Jackson序列化  json占用的内存最小 */
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        
        /**Jdk序列化   JdkSerializationRedisSerializer是最高效的*/
        // JdkSerializationRedisSerializer jdkSerializationRedisSerializer = new JdkSerializationRedisSerializer();
        
        /**String序列化*/
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
		
		/**
		 * 设置不同数据类型的序列化方式
		 * /
		
        /**将key value 进行stringRedisSerializer序列化*/
        redisTemplate.setKeySerializer(stringRedisSerializer);
        redisTemplate.setValueSerializer(stringRedisSerializer);
        
        /**将HashKey HashValue 进行序列化*/
        redisTemplate.setHashKeySerializer(stringRedisSerializer);
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
        
        redisTemplate.afterPropertiesSet();
		return redisTemplate;
    }
}

3.RedisTemplate常用方法

  1. redisTemplate.opsForValue()

//返回操作string类型的Operations
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
operations.set(key, value);

  1. redisTemplate.expire()

//setnx 设置超时时间
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
operations.set(key, value);
redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);

  1. redisTemplate.delete(key); //删除一个key

  2. redisTemplate.hasKey(key); //检查是否存在一个key

  3. redisTemplate.opsForHash()

//返回操作hah类型的Operations
HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
hash.put(key, hashKey, value);

  1. redisTemplate.opsForSet()

//返回操作set类型的Operations
SetOperations<String, Object> set = redisTemplate.opsForSet();
set.add(key, value)

  1. redisTemplate.opsForZSet()

//返回操作zset类型的Operations
ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
zset.add(key, value, scoure)

//有序集合获取排名
ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
Set<ZSetOperations.TypedTuple> ret = zset.rangeWithScores(key,start,end);

  • 注意:
    所有对元素的增删改查都不是直接用RedisTemplate的方法 用都是的RedisTemplate返回的"Operations"的方法 且五种类型的方法各不相同

四.Redis作为springBoot二级缓存

1.依赖:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
                 <groupId>org.springframework.boot</groupId>
                 <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>

2.在applicaton.yml中配置好redis的连接

spring.redis.database=0
#Redis服务器地址
spring.redis.host=xxx.xxx.xxx.xxx
#Redis服务器连接端口
spring.redis.port=6379
#Redis服务器连接密码(默认为空)
spring.redis.password=xxx

3.给启动类加注解启动二级缓存:

@EnableCaching

4.在根目录新建RedisConfig.java:

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory){
        RedisTemplate<String, String> redisTemplate = new RedisTemplate<String,String>();
        redisTemplate.setConnectionFactory(factory);
        
        // 使用Jackson2JsonRedisSerialize 替换默认序列化
        /**Jackson序列化  json占用的内存最小 */
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        
        /**Jdk序列化   JdkSerializationRedisSerializer是最高效的*/
        // JdkSerializationRedisSerializer jdkSerializationRedisSerializer = new JdkSerializationRedisSerializer();
        
        /**String序列化*/
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
		
		//设置序列化类型
        /**将key value 进行stringRedisSerializer序列化*/
        redisTemplate.setKeySerializer(stringRedisSerializer);
        redisTemplate.setValueSerializer(stringRedisSerializer);
        
        /**将HashKey HashValue 进行序列化*/
        redisTemplate.setHashKeySerializer(stringRedisSerializer);
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
        
        redisTemplate.afterPropertiesSet();
		return redisTemplate;
    }

	//注入redis中key的生成方式 到时可以在方法的注解上直接调用
    @Bean
    public KeyGenerator simpleKeyGenerator() {
        return (o, method, objects) -> {
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.append(o.getClass().getSimpleName());
            stringBuilder.append(".");
            stringBuilder.append(method.getName());
            stringBuilder.append("[");
            for (Object obj : objects) {
                stringBuilder.append(obj.toString());
            }
            stringBuilder.append("]");

            return stringBuilder.toString();
        };
    }

	//配置CacheManager 
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
        return new RedisCacheManager(
                RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory),
                this.getRedisCacheConfigurationWithTtl(600), // 默认策略,未配置的 key 会使用这个
                this.getRedisCacheConfigurationMap() // 指定 key 策略
        );
    }
	
	//自定缓存策略
    private Map<String, RedisCacheConfiguration> getRedisCacheConfigurationMap() {
        Map<String, RedisCacheConfiguration> redisCacheConfigurationMap = new HashMap<>();
        /**
         *可以通过@Cacheable、@CachPut、@CachEvict注解中的value找到对应方法 然后设置过期时间
         */
        redisCacheConfigurationMap.put("在使用Cach注解的方法的value", this.getRedisCacheConfigurationWithTtl(100));//单位是秒
        redisCacheConfigurationMap.put("在使用Cach注解的方法的value", this.getRedisCacheConfigurationWithTtl(18000));

        return redisCacheConfigurationMap;
    }

	//给自定缓存策略设置序列化方式以及过期时间
    private RedisCacheConfiguration getRedisCacheConfigurationWithTtl(Integer seconds) {
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);

        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
        redisCacheConfiguration = redisCacheConfiguration.serializeValuesWith(
        		//设置序列化方式
                RedisSerializationContext
                        .SerializationPair
                        .fromSerializer(jackson2JsonRedisSerializer)
        ).entryTtl(Duration.ofSeconds(seconds));  //设置过期时间

        return redisCacheConfiguration;
    }

}

5.给要开启二级缓存的类注解

@CachConfig(cachNames=" ")
注意:该注解时为了在redis存储时设置名字前缀 如果每个方法的的Cach相关注解有value的话可以不用在类上加该注解

6.给要开启的方法注解(该方法必须有返回值)

@Cacheable(value=" ",keyGenerator=“simpleKeyGenerator”)
每次更新缓存前查询是否缓存中已经存在 不存在才执行该方法 并且将返回值刷新为本次执行的返回值

@CachPut(value=" ",keyGenerator=“simpleKeyGenerator”)
每次都执行 不管缓存中是否存在

@CachEvict(value=" ",keyGenerator=“simpleKeyGenerator”)
删除缓存名为simpleKeyGenerator拼接后得到的key对应的value

注意:

  • 不使用(value=" “,keyGenerator=“simpleKeyGenerator”)这个组合配置key
    如果只用(key=”#p下标"+"#p下标".字段名)所得的key是“cacheNames的值::对应下标参数的值)很容易重复 还有下标从0开始
  • 注解中value的值用于在自定缓存策略时找到对应的方法 在设置好value之后 可以去修改getRedisCacheConfigurationMap()那里 加入该方法
  • key的生成方式simpleKeyGenerator 是前面配置中注入的生成方式
  • 如果不想返回的空值更新到会缓存里 注解里加一条”unless="#result==null“

五.分布式session

1.原因:

  1. 因为每个浏览器和服务器建立连接之后都会有一个session 然后可以给session里面添加值来作一些验证,但是每个session默认存储在访问的服务器的内存中 如果分布式多机器部署的话一个连接会产生多个session 所以把所以session都保存在redis中

  2. 引入依赖并配置之后 springboot会自己把创建的session保存在redis 每次通过request获取session也会从redis中获取 而不是本机内存

  3. 并且每次访问服务器都会自动把过期时间重置为初始值

    注意:
    如果是前后端分离跨域就不适用,可以通过:

    • 手动放入(key: 唯一标识的token、value: User信息),每次获取也要手动从redist获取
    • 或者使用shiro+redis 生成分布式session ( 配置其SessionManger )
      登陆成功之后才生成session 用 Session session = SecurityUtils.getSubject().getSession() 获得session 但没有登陆就没subject 将空指针异常

2.依赖

    <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-session-data-redis</artifactId>
        </dependency>

3.使用:
给启动类加注解

@EnableHttpSession(maxInactiveIntervalInSeconds= 过期时间(单位:秒))

注意:

  • session-data-redis的分布式session:只要连上服务器就会把session缓存到数据库
  • shiro+redis的session的分布式session:登陆成功才有
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值