Redis学习8——与springboot结合

在Spring Boot中配置和使用Redis

一、在Spring Boot中配置Redis

配置Redis服务器,只需要在配置文件application.properties中加入:

在Spring Boot中配置Redis:

#配置连接池属性
spring.redis.jedis.pool.min-idle=5
spring.redis.jedis.pool.max-active=10
spring.redis.jedis.pool.max-idle=10
spring.redis.jedis.pool.max-wait=2000
#配置Redis服务器属性
spring.redis.port=6379
spring.redis.host=192.168.11.131
spring.redis.password=123456
#Redis连接超时时间,单位毫秒
spring.redis.timeout=1000

配置连接池和服务器的属性,用以连接Redis服务器,这样Spring Boot的自动装配机制就会读取这些配置来生成有关Redis的操作对象,它会自动生成RedisConnectionFactory、RedisTemplate、StringRedisTemplate等常用的Redis对象。

RedisTemplate会默认使用JdkSerializationRedisSerializer进行序列化键值,此时Redis服务器存入的便是一个经过序列化后的特殊字符串,对于我们跟踪并不是很友好。
考虑使用StringRedisTemplate,能够支持字符串,但不能支持Java对象的存储,为了克服这个问题,可以通过设置RedisTemplate的序列化器来处理。

在Spring Boot的启动文件中修改RedisTemplate的序列化器:

package com.springboot.chapter7.main;
/**** imports ****/
@SpringBootApplication(scanBasePackages = "com.springboot.chapter7")
public class Chapter7Application {

    // 注入RedisTemplate
    @Autowired
    private RedisTemplate redisTemplate = null;

    // 定义自定义后初始化方法
    @PostConstruct
    public void init() {
        initRedisTemplate();
    }

    // 设置RedisTemplate的序列化器
    private void initRedisTemplate() {
        RedisSerializer stringSerializer = redisTemplate.getStringSerializer();
        redisTemplate.setKeySerializer(stringSerializer);
        redisTemplate.setHashKeySerializer(stringSerializer);
    }

    ......
}

首先通过@Autowired注入由Spring Boot根据配置生成的RedisTemplate对象,
然后利用Spring Bean生命周期的特性使用注解@PostConstruct自定义后初始化方法。
方法里,把RedisTemplate中的键序列化器修改为StringRedisSerializer。因为之前我们讨论过,在RedisTemplate中它会默认地定义了一个StringRedisSerializer对象,
所以这里我并没有自己创建一个新的StringRedisSerializer对象,而是从RedisTemplate中获取。
然后把RedisTemplate关于键和其散列数据类型的filed都修改为了使用StringRedisSerializer进行序列化,这样Redis服务器上得到的键和散列的field就都以字符串存储了。

二、操作Redis数据类型

操作Redis字符串和散列数据

@Controller
@RequestMapping("/redis")
public class RedisController {

    @Autowired
    private RedisTemplate redisTemplate = null;

    @Autowired
    private StringRedisTemplate stringRedisTemplate = null;

       @RequestMapping("/stringAndHash")
    @ResponseBody
    public Map testStringAndHash() {
        redisTemplate.opsForValue().set("key1", "value1");
        // 注意这里使用了JDK的序列化器,所以Redis保存时不是整数,不能运算
        redisTemplate.opsForValue().set("int_key", "1");
        stringRedisTemplate.opsForValue().set("int", "1");
        //设置超时时间
        stringRedisTemplate.opsForValue().set("name","aa",2, TimeUnit.MINUTES);
        //将对象转为json字符串来存储
        AppUserEntity userEntity = AppUserEntity.builder().name("aa").build();
        stringRedisTemplate.opsForValue().set("user", JSONObject.toJSONString(userEntity));
        stringRedisTemplate.opsForValue().get("user");
        // 使用运算
        stringRedisTemplate.opsForValue().increment("int", 1);
        Map hash = new HashMap();
        hash.put("field1", "value1");
        hash.put("field2", "value2");
        // 存入一个散列数据类型
        stringRedisTemplate.opsForHash().putAll("hash", hash);
        // 新增一个字段
        stringRedisTemplate.opsForHash().put("hash", "field3", "value3");
        // 绑定散列操作的key,这样可以连续对同一个散列数据类型进行操作
        BoundHashOperations hashOps = stringRedisTemplate.boundHashOps("hash");
        // 删除两个字段
        hashOps.delete("field1", "field2");
        // 新增一个字段
        hashOps.put("field4", "value5");
        Map map = new HashMap();
        map.put("success", true);
        return map;
    }
    ....
}

这里的@Autowired注入了Spring Boot为我们自动初始化RedisTemplate和StringRedisTemplate对象。
看到testStringAndHash方法,首先是存入了一个“key1”的数据,然后是“int_key”。但是请注意这个“int_key”存入到Redis服务器中,因为采用了JDK序列化器,所以在Redis服务器中它不是整数,而是一个被JDK序列化器序列化后的二进制字符串,没有办法使用Redis命令进行运算的。StringRedisTemplate对象保存的键为“int”的整数,因为使用了String序列化器,可以进行运算。
然后是操作散列数据类型,在插入多个散列的field时可以采用Map,然后为了方便对同一个数据操作,这里代码还获取了BoundHashOperations对象进行操作,这样对同一个数据操作就方便许多了。

列表也是常用的数据类型。在Redis中列表是一种链表结构,查询性能不高,而增删节点的性能高,存在从左到右或者从右到左的操作。

操作列表(链表)

@RequestMapping("/list")
@ResponseBody
public Map testList() {
    // 插入两个列表,注意它们在链表的顺序
    // 链表从左到右顺序为v10,v8,v6,v4,v2
    stringRedisTemplate.opsForList().leftPushAll(
          "list1", "v2", "v4", "v6", "v8", "v10");
    // 链表从左到右顺序为v1,v2,v3,v4,v5,v6
    stringRedisTemplate.opsForList().rightPushAll(
          "list2", "v1", "v2", "v3", "v4", "v5", "v6");
    // 绑定list2链表操作
    BoundListOperations listOps = stringRedisTemplate.boundListOps("list2");
	// 从右边弹出一个成员
    Object result1 = listOps.rightPop();
    // 获取定位元素,Redis从0开始计算,这里值为v2
    Object result2 = listOps.index(1);
    // 从左边插入链表
    listOps.leftPush("v0");
    // 求链表长度
    Long size = listOps.size();
    // 求链表下标区间成员,整个链表下标范围为0到size-1,这里不取最后一个元素
    List elements = listOps.range(0, size-2);
    Map map = new HashMap();
    map.put("success", true);
    return map;
}

上述操作是基于StringRedisTemplate的,保存到Redis服务器的都是字符串类型,有两点需要注意:列表元素的顺序问题,是从左到右还是从右到左;下标问题,在Redis中是以0开始的。

接着是集合,它在Redis中是不允许成员重复,数据结构上是一个散列表的结构,所以它是无序的,对于两个或者以上的集合,Redis还提供了交集、并集和差集的运算。

操作集合:

@RequestMapping("/set")
@ResponseBody
public Map testSet() {
    // 请注意:这里v1重复两次,因为集合不允许重复,所以只是插入5个成员到集合中
    stringRedisTemplate.opsForSet().add("set1", 
         "v1","v1","v2","v3","v4","v5");
    stringRedisTemplate.opsForSet().add("set2", "v2","v4","v6","v8");
    // 绑定set1集合操作
    BoundSetOperations setOps = stringRedisTemplate.boundSetOps("set1");
    // 增加两个元素
    setOps.add("v6", "v7");
    // 删除两个元素
    setOps.remove("v1", "v7");
    // 返回所有元素
    Set set1 = setOps.members();
    // 求成员数
    Long size = setOps.size();
    // 求交集
    Set inter = setOps.intersect("set2");
    // 求交集,并且用新集合inter保存
    setOps.intersectAndStore("set2", "inter");
    // 求差集
    Set diff = setOps.diff("set2");
    // 求差集,并且用新集合diff保存
    setOps.diffAndStore("set2", "diff");
    // 求并集
    Set union = setOps.union("set2");
    // 求并集,并且用新集合union保存
    setOps.unionAndStore("set2", "union");
    Map map = new HashMap();
    map.put("success", true);
    return map;
}

这里在添加集合set1时,存在两个v1一样的元素。因为集合不允许重复。

在一些网站中,经常会有排名,如最热门的商品或者最大的购买买家,都是常常见到的场景。对于这类排名,刷新往往需要及时,也涉及较大的统计,如果使用数据库会太慢。

为了支持集合的排序,Redis还提供了有序集合(zset)。有序集合与集合的差异并不大,它也是一种散列表存储的方式,同时它的有序性只是靠它在数据结构中增加一个属性——score(分数)得以支持。为了支持这个变化,Spring提供了TypedTuple接口,它定义了两个方法,并且Spring还提供了其默认的实现类DefaultTypedTuple:

Redis学习8——与springboot结合_第1张图片

在TypedTuple接口的设计中,value是保存有序集合的值,score则是保存分数,Redis是使用分数来完成集合的排序的,这样如果把买家作为一个有序集合,而买家花的钱作为分数,
就可以使用Redis进行快速排序了:

操作有序集合:

@RequestMapping("/zset")
@ResponseBody
public Map testZset() {
    Set> typedTupleSet = new HashSet<>();
    for (int i=1; i<=9; i++) {
        // 分数
        double score = i*0.1;
        // 创建一个TypedTuple对象,存入值和分数
        TypedTuple typedTuple 
            = new DefaultTypedTuple("value" + i, score);
        typedTupleSet.add(typedTuple);
    }
    // 往有序集合插入元素
    stringRedisTemplate.opsForZSet().add("zset1", typedTupleSet);
    // 绑定zset1有序集合操作
    BoundZSetOperations zsetOps 
          = stringRedisTemplate.boundZSetOps("zset1");
    // 增加一个元素
    zsetOps.add("value10", 0.26);
    Set setRange = zsetOps.range(1, 6);
    // 按分数排序获取有序集合
    Set setScore = zsetOps.rangeByScore(0.2, 0.6);
    // 定义值范围
    Range range = new Range();
    range.gt("value3");// 大于value3
    // range.gte("value3");// 大于等于value3
    // range.lt("value8");// 小于value8
    range.lte("value8");// 小于等于value8
    // 按值排序,请注意这个排序是按字符串排序
    Set setLex = zsetOps.rangeByLex(range);
    // 删除元素
    zsetOps.remove("value9", "value2");
    // 求分数
    Double score = zsetOps.score("value8");
    // 在下标区间下,按分数排序,同时返回value和score
    Set> rangeSet = zsetOps.rangeWithScores(1, 6);
    // 在分数区间下,按分数排序,同时返回value和score
    Set> scoreSet = zsetOps.rangeByScoreWithScores(1, 6);
	// 按从大到小排序
    Set reverseSet = zsetOps.reverseRange(2, 8);
    Map map = new HashMap();
    map.put("success", true);
    return map;
}

TypedTuple用来保存有序集合的元素,在默认的情况下,有序集合是从小到大地排序的,按下标、分数和值进行排序获取有序集合的元素,或者连同分数一起返回,有时候还可以进行从大到小的排序,只是在使用值排序时,我们可以使用Spring为我们创建的Range类,它可以定义值的范围,还有大于、等于、大于等于、小于等于等范围定义,方便我们筛选对应的元素。

地理位置和基数不是我们常用的功能,此处忽略。

你可能感兴趣的:(redis)