properties文件配置

#配置连接池属性
#连接池最小空闲连接数
spring.redis.jedis.pool.min-idle=5
#连接池最大空闲连接数
spring.redis.jedis.pool.max-idle=10
#连接池最大连接数
spring.redis.jedis.pool.max-active=10
#连接池最大阻塞等待时间
spring.redis.jedis.pool.max-wait=2000
#配置redis服务器属性
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=123456
spring.redis.timeout=1000

springboot通过自动装配机制读取配置文件,生成有关的redis操作对象,自动生产RedisConnectionFactory,RedisTemplate,stringRedisTemplate。

RedisTemplate会默认使用JdkSerializationRedisSerializer对键值对进行序列化操作,这样便能存储到Redis服务器中。

RedisTemplate中的序列化器属性

redisTemplate 连接 释放 redistemplate连接池配置_spring

有时候我们需要连续操作一个散列数据类型或者列表多长,这时Spring也提供支持,它提供了对应的BoundXXXOperations接口。

redisTemplate 连接 释放 redistemplate连接池配置_Redis_02

SessionCallback和RedisCallback接口,它们的作用是让RedisTemplate进行回调,通过他们可以在同一条连接下执行多个Redis命令。其中SessionCallback提供了良好的封装,对于开发者比较友好,

因此在实际开发中优先选择使用它,相对而言,RedisCallback接口比较底层层次,需要处理的内容比较多,可读性较差,所以在必要的时候尽量不选择使用它。

1.修改RedisTemplate序列化器

@Configuration
public class RedisConfig {

    @Autowired
    private RedisTemplate redisTemplate;

    @PostConstruct
    public void init(){
        initRedisTemplate();
    }

    private void initRedisTemplate(){
        RedisSerializer redisSerializer = redisTemplate.getStringSerializer();
        //对RedisTemplate的默认序列化进行修改
        redisTemplate.setKeySerializer(redisSerializer);
        redisTemplate.setHashKeySerializer(redisSerializer);
    }
}

2.4中数据类型的用法

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

    private static final Logger logger = LoggerFactory.getLogger(RedisController.class);

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @RequestMapping("/string")
    @ResponseBody
    public Map<String,Object> testStringAndHash(){
        redisTemplate.opsForValue().set("key1","value1");
        //JDK的序列化器,所以redis保存时不是整数,不能运算
        redisTemplate.opsForValue().set("int_key","1");
        stringRedisTemplate.opsForValue().set("int","1");
        //使用运算
        stringRedisTemplate.opsForValue().increment("int",1);
        //获取底层Jedis连接
//        Jedis jedis = (Jedis)stringRedisTemplate.getConnectionFactory().getConnection().getNativeConnection();
//        //减1操作,这个命令RedisTemplate不支持,所以先获取底层的连接再操作
//        jedis.decr("int");
        //存入一个散列数据类型
        Map<String,String> hash = new HashMap<>();
        hash.put("field1","value1");
        hash.put("field2","value2");
        stringRedisTemplate.opsForHash().putAll("hash",hash);
        //新增一个字段
        stringRedisTemplate.opsForHash().put("hash","field3","value3");
        //绑定散列操作的key,这样可以连续对同一个散列数据类型进行操作
        BoundHashOperations hashOperations = stringRedisTemplate.boundHashOps("hash");
        //删除两个字段
        hashOperations.delete("field1","field2");
        //新增一个字段
        hashOperations.put("filed4","value5");
        return null;

    }

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

    @RequestMapping("/set")
    @ResponseBody
    public String testSet(){
        //这里v1重复两次,集合中不允许重复,所以只插入5个成员到集合中
        stringRedisTemplate.opsForSet().add("set1","v1","v1","v2","v3","v4","v5");
        stringRedisTemplate.opsForSet().add("set2","v2","v4","v6","v8");
        BoundSetOperations setOps = stringRedisTemplate.boundSetOps("set1");
        //增加两个元素
        setOps.add("v6","v7");
        //删除元素
        setOps.remove("v1","v7");
        //返回所有元素
        Set set1 = setOps.members();
        //集合大小
        Long size = setOps.size();
        //求交集,set1和set2中的重复元素
        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");
        return null;
    }

    @RequestMapping("/zset")
    @ResponseBody
    public String testZset(){
        Set<ZSetOperations.TypedTuple<String>> typedTupleSet = new HashSet<>();
        for(int i=1; i<=9; i++){
            //分数
            double score = i * 0.1;
            ZSetOperations.TypedTuple<String> typedTuple
                    =new DefaultTypedTuple<>("value" + i, score);
            typedTupleSet.add(typedTuple);
        }
        //往有序集合插入元素
        stringRedisTemplate.opsForZSet().add("zset1",typedTupleSet);
        //绑定zset1有序集合操作
        BoundZSetOperations<String,String> zsetOps
                = stringRedisTemplate.boundZSetOps("zset1");
        //增加一个元素
        zsetOps.add("value10",0.26);
        Set<String> setRange = zsetOps.range(1,6);
        //按分数排序获取有序集合
        Set<String> 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<String> setLex = zsetOps.rangeByLex(range);
        //删除元素
        zsetOps.remove("value9","value2");
        //求分数
        Double score = zsetOps.score("value8");
        //在下标区间下,按分数排序,同时返回value和score
        Set<ZSetOperations.TypedTuple<String>> rangSet = zsetOps.rangeWithScores(1,6);
        //在分数区间下,按分数排序,同时返回value和score
        Set<ZSetOperations.TypedTuple<String>> scoreSet = zsetOps.rangeByScoreWithScores(1,6);
        //按从小到大排序
        Set<String> reverseSet = zsetOps.reverseRange(2,8);
        
        return "";
    }

}

使用Redis事务

Redis是支持一定事务的能力的NoSQL,在Redis中使用事务,通常的命令组合是watch...multi...exec,也就是要在一个Redis连接中执行多个命令,这时候可以使用SessionCallback接口。其中

watch命令是可以监控Redis的一些键;multi命令是开始事务,开始事务后,客户端的命令不会马上被执行,而是存放在一个队列里面,也就是在这时我们执行一些返回数据的命令,Redis也是不会马上执行的,

而是把命令放到一个队列里面,所以此时调用Redis的命令,结果都是返回null;exec命令的意义在于执行事务,只是它在队列命令执行前会判断watch监控的Redis的键的数据是否发生过变化,如果发生变化

Redis就会取消事务,否则就会执行事务,Redis在执行事务时,要么全部执行,要么全部不执行,而且不会被其他客户端打断,这样就保证了Redis事务下数据的一致性。

redisTemplate 连接 释放 redistemplate连接池配置_Redis_03

 

 

@RequestMapping("multi")
    @ResponseBody
    public String testMulti(){
        redisTemplate.opsForValue().set("key1","value1");

        List list = (List)redisTemplate.execute((RedisOperations operations)->{
            //设置要监控key1
            operations.watch("key1");
            //开启事务,在exec命令执行前,全部都只是进入队列
            operations.multi();
            operations.opsForValue().set("key2","value2");
            //获取值将为null,因为reids只是把命令放入队列
            Object value2 = operations.opsForValue().get("key2");
            System.out.println("命令在队列,所以value为null【"+value2+"】");
            operations.opsForValue().set("key3","value3");
            Object value3 = operations.opsForValue().get("key3");
            System.out.println("命令在队列,所以value为null【"+value3+"】");
            //执行exec命令,将现判断key1是否在监控后被修改过,如果是则不执行事务,否则就执行事务
            return operations.exec();
        });
        System.out.println(list);
        return "";
    }

redis发布订阅

redisTemplate 连接 释放 redistemplate连接池配置_Redis_04