0121 spring-boot-redis的使用


redis是什么呢?redis,属于NoSQL的一种,在互联网时代,起到加速系统的作用。

redis是一种内存数据库,支持7种数据类型的存储,性能1S 10w次读写;
redis提供的简单的事务保证了高并发场景下数的一致性。
redis在2.6版本之后增加了lua支持,命令是原子性的;

本篇文章主要基于springboot的redis-starter。
HELLO, 性能利器Redis.

spring-boot-starter-redis


这个是springboot提供的redis操作工具包,底层的redis驱动使用的是lettus,而不是jedis;

依赖


    org.springframework.boot
    spring-boot-starter-data-redis

序列化

主要通过RedisTemplate来操作redis;

当然也支持自定义序列化器,比如效率比较高的kyto序列化器;
StringRedisTemplate:key,value都是按照字符串存储的。
TypedTuple 保存集合中的有序元素;
可以查看一下StringRedisTemplate的源码:

public StringRedisTemplate() {
	setKeySerializer(RedisSerializer.string());
	setValueSerializer(RedisSerializer.string());
	setHashKeySerializer(RedisSerializer.string());
	setHashValueSerializer(RedisSerializer.string());
}

数据类型操作接口

功能 单个操作接口 批量操作接口
有序集合 ZSetOperations BoundZsetOperations
字符串 ValueOperations BoundValueOpetations
集合 SetOperations BoundSetOperations
列表 ListOperations BoundListOperations
散列 HashOperations BoundHashOperations
基数 HyperLogLogOperations BoundHyperLogLogOperaions
地理位置 GeoOperations BoundGeoOperations

使用代码

 @Autowired
    private RedisTemplate redisTemplate;

    @Test
    void stringRedisTest() {
        final ValueOperations valueOperations = redisTemplate.opsForValue();
        valueOperations
                .set("key1", "value1", Duration.ofMinutes(1));

        final Object value = valueOperations.get("key1");

        Assert.isTrue(Objects.equals("value1", value), "set失败");

        final HashOperations hashOperations = redisTemplate.opsForHash();

        hashOperations.put("hash1", "f1", "v1");
        hashOperations.put("hash1", "f2", "v2");

        hashOperations.values("hash1").forEach(System.out::println);
    }

在同一条连接中进行多次操作

  1. SessionCallback 高级操作对象
  2. RedisCallback   低级操作对象

    代码中直接使用的java8的lambda表达式。

使用代码

@Test
void redisCallbackTest() {
    redisTemplate.execute((RedisCallback) connection -> {
        connection.set("rkey1".getBytes(), "rv1".getBytes());
        connection.set("rkey2".getBytes(), "rv2".getBytes());
        return null;
    });
}

@Test
void sessionCallbackTest() {
    redisTemplate.execute(new SessionCallback() {
        @Override
        public Object execute(RedisOperations operations) throws DataAccessException {
            final ListOperations listOperations = operations.opsForList();
            listOperations.leftPush("sk1", "sv1");
            listOperations.leftPush("sk1", "sv2");
            listOperations.getOperations().expire("sk1", 1, TimeUnit.MINUTES);

            listOperations.range("sk1", 0, 2).forEach(System.out::println);
            return 1;
        }
    });
}

字符串操作

最为常用的数据类型
实际情况使用的不多,现实的场景一般是放一个对象或者对象列表 转换为字符串 进行存储,取出的时候再转换为对象;

代码:

 @Test
    void stringTest() {
        redisTemplate.opsForValue().set("stringKey1", "value1", 5, TimeUnit.MINUTES);

        //字符串类型的整数,不能进行数字运算;
        redisTemplate.opsForValue().set("stringKey2", "1", 5, TimeUnit.MINUTES);

        //进行数字运算,增加,减少
        redisTemplate.opsForValue().set("stringKey3", 1, 5, TimeUnit.MINUTES);
        redisTemplate.opsForValue().increment("stringKey3",1);
        redisTemplate.opsForValue().decrement("stringKey3",1);

        //其它操作方法
        final Long keySize = redisTemplate.opsForValue().size("stringKey1");
        System.out.println(keySize);
        
        //批量设置
        Map map = new HashMap<>(4);
        map.put("sk1",1L);
        map.put("sk2",2L);
        map.put("sk3",3L);
        map.put("sk4",4L);
        redisTemplate.opsForValue().multiSet(map);
        redisTemplate.opsForValue().multiSetIfAbsent(map);
        //批量获取
        redisTemplate.opsForValue().multiGet(map.keySet()).forEach(System.out::println);


        //getAndSet
        final Object sk5Value = redisTemplate.opsForValue().getAndSet("sk5", 100);
        System.out.println("sk5Value:"+sk5Value);
        
        redisTemplate.opsForValue().append("sk5","hello redis");
        System.out.println("sk5Value2:"+redisTemplate.opsForValue().get("sk5"));
        
        //按照情况设置,可以省去了之前查询出来之后判断是否存在再操作的代码;
        redisTemplate.opsForValue().setIfAbsent("sk6",1000,5,TimeUnit.MINUTES);
        redisTemplate.opsForValue().setIfPresent("sk6",100,5,TimeUnit.MINUTES);

    }

其它方法:

更多提供的方法需要在业务场景中多使用

列表操作

 @Test
    void listTest() {

        stringRedisTemplate.opsForList().leftPush("lk1","lkv1");
        stringRedisTemplate.opsForList().leftPushAll("lk2","lk2v1","lk2v2");
        stringRedisTemplate.opsForList().leftPushAll("lk2",Arrays.asList("lk2v3","lk2v4"));
        stringRedisTemplate.opsForList().leftPushIfPresent("lk3","lk3v1");

        final List lk2ValuesList = stringRedisTemplate.opsForList().range("lk2", 0, 3);
        System.out.println(lk2ValuesList);
    }

集合操作

@Test
    void setTest() {
        stringRedisTemplate.opsForSet().add("sk1","sk1v1","sk1v2","sk1v3");
        stringRedisTemplate.opsForSet().add("sk2","sk1v1","sk2v2","sk2v3");

        final Set sk1 = stringRedisTemplate.opsForSet().members("sk1");
        final Set sk2 = stringRedisTemplate.opsForSet().members("sk2");

        System.out.println("sk1: "+sk1);
        System.out.println("sk2: "+sk2);

        final Set intersect = stringRedisTemplate.opsForSet().intersect("sk1", "sk2");
        System.out.println("交集是:" + intersect);

        final Set union = stringRedisTemplate.opsForSet().union("sk1", "sk2");
        System.out.println("并集:" + union);

        final Set difference = stringRedisTemplate.opsForSet().difference("sk1", "sk2");
        System.out.println("差集:"+ difference);

        final Long size = stringRedisTemplate.opsForSet().size("sk1");

        System.out.println("size for sk1 : " + size);

        stringRedisTemplate.delete("sk1");
        stringRedisTemplate.delete("sk2");

    }

有序集合操作

 @Test
    void zsetTest() {
        IntStream.rangeClosed(1,100).forEach(i->{
            stringRedisTemplate.opsForZSet().add("zsk1",String.valueOf(i),i*10);
        });
        final Set> typedTupleSet = IntStream.rangeClosed(1, 100).mapToObj(i -> new DefaultTypedTuple(String.valueOf(i), (double) i * 11)).collect(Collectors.toSet());
        stringRedisTemplate.opsForZSet().add("zsk2",typedTupleSet);

        final Set zsk1 = stringRedisTemplate.opsForZSet().rangeByLex("zsk1", RedisZSetCommands.Range.range().gte(20).lte(100));
        System.out.println("范围内的集合:" + zsk1);

    }

散列表操作

 @Test
    void hashTest() {
        stringRedisTemplate.opsForHash().put("hashk1","k1","v1");
        stringRedisTemplate.opsForHash().put("hashk1","k2","v1");
        stringRedisTemplate.opsForHash().put("hashk1","k3","v1");

        stringRedisTemplate.opsForHash().putIfAbsent("hashk1","k4","new V1");

        final List multiGet = stringRedisTemplate.opsForHash().multiGet("hashk1", Arrays.asList("k1", "k2"));
        System.out.println("一次获取多个:" + multiGet);

 }

springboot中redis的配置

配置分两个部分,连接池和连接信息;下表列出必须给出的配置:

spring.redis.port=6379
spring.redis.host=localhost
spring.redis.password=
spring.redis.timeout=1000

#最小空闲连接数
spring.redis.lettuce.pool.min-idle=2
#最大空闲连接数
spring.redis.lettuce.pool.max-idle=4
#最大活跃连接数
spring.redis.lettuce.pool.max-active=8
#连接最长分配等待时间
spring.redis.lettuce.pool.max-wait=2000
#回收线程间隔毫秒数
spring.redis.lettuce.pool.time-between-eviction-runs=100

注解操作redis

配置CacheManager
spring.redis.cache.type=redis
spring.redis.cache.name=redisCache

通过注解@EnableCaching启用;
代码点我获取!

美女还是要给看的。

原创不易,转载请注明出处。