Springboot2.x版本下使用redis

1、pom文件

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-redis</artifactId>
   <exclusions>
      <exclusion>
         <artifactId>lettuce-core</artifactId>
         <groupId>io.lettuce</groupId>
      </exclusion>
   </exclusions>
</dependency>
<dependency>
   <groupId>redis.clients</groupId>
   <artifactId>jedis</artifactId>
</dependency>

备注: 排除掉 lettuce-core客户端工具,使用jedis工具

2、java类

RedisConfig.java----->

package fun.huanghai.redis.config;

import fun.huanghai.redis.listener.RedisMessageListener;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.ChannelTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.Topic;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import redis.clients.jedis.JedisPoolConfig;

@Configuration
public class RedisConfig implements ApplicationContextAware{

    private ApplicationContext applicationContext;

    //任务池
    private ThreadPoolTaskScheduler taskScheduler;

    @Bean
    public RedisConnectionFactory redisConnectionFactory(){
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxWaitMillis(2000);
        poolConfig.setMaxIdle(30);
        poolConfig.setMaxTotal(50);
        RedisConnectionFactory factory = new JedisConnectionFactory(poolConfig);
        return factory;
    }

    /**
     * 配置序列化器
     * @param //redisConnectionFactory
     * @return
     */
    @Bean
    public RedisTemplate<Object,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
        RedisTemplate<Object,Object> redisTemplate = new RedisTemplate<>();
        //RedisTemplate会自动初始化StringRedisSerializer,所以这里直接获取
        RedisSerializer<String> stringSerializer = redisTemplate.getStringSerializer();
        //设置字符串序列化器,这样Spring就会把Redis的key当做字符串处理了
        redisTemplate.setKeySerializer(stringSerializer);
        redisTemplate.setHashKeySerializer(stringSerializer);
        redisTemplate.setValueSerializer(stringSerializer);
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        return redisTemplate;

    }

    /**
     * 创建任务池,运行线程等待处理Redis的消息
     * @return
     */
    @Bean
    public ThreadPoolTaskScheduler taskScheduler(){
        if(taskScheduler!=null){
            return taskScheduler;
        }
        taskScheduler = new ThreadPoolTaskScheduler();
        taskScheduler.setPoolSize(20);
        return taskScheduler;
    }

    /**
     * redis消息监听容器
     * @param redisConnectionFactory
     * @return
     */
    @Bean
    public RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory redisConnectionFactory){
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        //redis连接工厂
        container.setConnectionFactory(redisConnectionFactory);
        //设置运行任务
        container.setTaskExecutor(taskScheduler);
        //定义监听渠道,名称为topic1
        Topic topic = new ChannelTopic("topic1");
        //使用监听器监听Redis的消息
        RedisMessageListener bean = applicationContext.getBean(RedisMessageListener.class);
        container.addMessageListener(bean,topic);

        return container;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

RedisMessageListener.java----->

package fun.huanghai.redis.listener;

import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;

@Component
public class RedisMessageListener implements MessageListener {

    @Override
    public void onMessage(Message message, @Nullable byte[] bytes) {
        //消息体
        String body = new String(message.getBody());
        //渠道名称
        String topic = new String(bytes);
        System.out.println(body);
        System.out.println(topic);
    }
}

RedisController.java---->

package fun.huanghai.redis.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisZSetCommands;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.lang.Nullable;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import redis.clients.jedis.Jedis;

import java.util.*;

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

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    //使用Redis的字符串(string)和哈希(hash)
    @GetMapping("/stringAndHash")
    public Map<String,Object> testStringAndHash(){
        Map<String,Object> map = new HashMap<>();

        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();

        //减一操作,这个命令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<String, Object, Object> hashOps = stringRedisTemplate.boundHashOps("hash");
        //删除2个字段
        hashOps.delete("field1","field2");
        //新增一个字段
        hashOps.put("field4","value4");

        map.put("success",true);

        return map;
    }

    //使用Redis的链表(列表)
    @RequestMapping("/list")
    public Map<String,Object> testList(){
        //插入2个列表,注意它们在链表的顺序
        //链表从左到右顺序为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<String, String> listOps = stringRedisTemplate.boundListOps("list2");

        //从右边弹出一个成员  v1,v2,v3,v4,v5
        Object r1 = listOps.rightPop();
        //获取定位元素,Redis从0开始计算,这里值为v2
        Object r2 = listOps.index(1);
        //从左边插入链表 v0,v1,v2,v3,v4,v5
        listOps.leftPush("v0");
        //求链表长度 6
        Long size = listOps.size();
        //求链表下标区间成员,整个链表下标范围为0到size-1,这里不取最后一个元素 v0,v1,v2,v3,v4
        List<String> elements = listOps.range(0, size - 2);


        Map<String,Object> map = new HashMap<>();
        map.put("success",true);
        map.put("list",elements);
        map.put("r1",r1);
        map.put("r2",r2);
        map.put("size",size);

        return map;
    }

    //使用Redis的集合
    @GetMapping("/set")
    public Map<String,Object> testSet(){
        //请注意:这里v1重复2次,因为集合不允许重复,所以只是插入5个成员到集合中
        stringRedisTemplate.opsForSet().add("set1","v1","v1",
                "v2","v3","v4","v5");

        stringRedisTemplate.opsForSet().add("set2","v2","v4","v6","v8");

        //绑定set1集合操作
        BoundSetOperations<String, String> setOps = stringRedisTemplate.boundSetOps("set1");
        //增加2个元素 v1,v2,v3,v4,v5,v6,v7
        setOps.add("v6","v7");
        //删除2个元素 v2,v3,v4,v5,v6
        setOps.remove("v1","v7");
        //返回所有元素 v2,v3,v4,v5,v6
        Set<String> set1 = setOps.members();
        //求成员数 5
        Long size = setOps.size();
        //求交集 v2,v4,v6
        Set<String> set2 = setOps.intersect("set2");
        //求交集,并且用新集合inter保存 v2,v4,v6
        setOps.intersectAndStore("set2","inter");
        //求差集 v3,v5
        Set<String> diff = setOps.diff("set2");
        //求差集,并且用新集合diff保存
        setOps.diffAndStore("set2","diff");
        //求并集 v2,v3,v4,v5,v6,v8
        Set<String> union = setOps.union("set2");
        //求并集,并且用新集合union保存
        setOps.unionAndStore("set2","union");


        Map<String,Object> map = new HashMap<>();
        map.put("success",true);
        map.put("set1",set1);
        map.put("size",size);
        map.put("inter",set2);
        map.put("diff",diff);
        map.put("union",union);
        return map;
    }

    //使用Redis的有序结合
    @GetMapping("/zset")
    public Map<String,Object> testZset(){
        Set<ZSetOperations.TypedTuple<String>> typedTupleSet = new HashSet<>();
        for (int i = 0; i < 9; i++) {
            //分数
            double scope = i*0.1;
            //创建一个TypedTuple对象,存入值和分数
            ZSetOperations.TypedTuple<String> typedTuple = new DefaultTypedTuple<>("value"+i,scope);
            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> setScope = zSetOps.rangeByScore(0.2, 0.6);
        //定义值范围
        RedisZSetCommands.Range range = new RedisZSetCommands.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>> scoreSet = zSetOps.rangeWithScores(1, 6);
        //按从大到小排序
        Set<String> reverseSet = zSetOps.reverseRange(2, 8);


        Map<String,Object> map = new HashMap<>();
        map.put("success",true);
        map.put("setRange",setRange);
        map.put("setScope",setScope);
        map.put("setLex",setLex);
        map.put("scoreSet",scoreSet);
        map.put("reverseSet",reverseSet);
        map.put("score",score);
        return map;
    }

    //使用Redis流水线测试性能
    @RequestMapping("/multi")
    public Map<String,Object> testMulti(){
        redisTemplate.opsForValue().set("key1","value1");


        List list = (List) redisTemplate.execute(new SessionCallback() {
            @Nullable
            @Override
            public Object execute(RedisOperations ro) throws DataAccessException {
                //设置要监控的key1
                ro.watch("key1");
                //开启事务,在exec命令执行前,全部都只是进入队列
                ro.multi();;
                ro.opsForValue().set("key2","vlue2");
                ro.opsForValue().increment("key1",1);
                //获取值将为null,因为redis只是把命令放入队列
                Object key2 = ro.opsForValue().get("key2");
                System.out.println("命令在队列,所以value为null【"+key2+"】");
                ro.opsForValue().set("key3","value3");
                Object key3 = ro.opsForValue().get("key3");
                System.out.println("命令在队列,所以value为null【"+key3+"】");
                //执行exec命令,将先判别key1是否在监控后被修改过,如果是则不执行事务,否则就执行事务
                return ro.exec();

            }
        });

        System.out.println(list);

        Map<String,Object> map = new HashMap<>();
        map.put("success",true);
        return map;
    }

    //使用Redis流水线测试性能
    @RequestMapping("/pipeline")
    public Map<String,Object> testPipeline(){

        long start = System.currentTimeMillis();
        List list = redisTemplate.executePipelined(new SessionCallback<Object>() {
            @Nullable
            @Override
            public Object execute(RedisOperations ro) throws DataAccessException {
                for (int i = 0; i < 10000; i++) {
                    ro.opsForValue().set("pipeline_"+i,"value_"+i);
                    String value = (String) ro.opsForValue().get("pipeline_"+i);
                    if(i==10000){
                        System.out.println("命令只是进入队列,所以值为空【"+value+"】");
                    }
                }

                return null;
            }
        });

        long end = System.currentTimeMillis();
        System.out.println("耗时:"+(end-start)+"毫秒。");
        Map<String,Object> map = new HashMap<>();
        map.put("success",true);
        return map;
    }

    /**
     * 发送消息到redis中(订阅模式)
     * @param body
     * @return
     */
    @GetMapping("/message")
    public Map<String,Object> testMessage(String body){

        redisTemplate.convertAndSend("topic1",body);
        Map<String,Object> map = new HashMap<>();
        map.put("success",true);
        return map;
    }

    //使用lua脚本
    @GetMapping("/lua")
    public Map<String,Object> testLua(){
        DefaultRedisScript<String> redisScript = new DefaultRedisScript<>();
        //设置脚本
        redisScript.setScriptText("return 'Hello Redis'");
        //定义返回类型,注意: 如果没有这个定义,Spring不会返回结果
        redisScript.setResultType(String.class);
        RedisSerializer stringSerializer = redisTemplate.getStringSerializer();
        //执行lua脚本
        Object obj = redisTemplate.execute(redisScript, stringSerializer, stringSerializer, null);
        Map<String,Object> map = new HashMap<>();
        map.put("success",true);
        map.put("res",obj);
        return map;
    }

    //使用lua脚本
    @GetMapping("/lua2")
    public Map<String,Object> testLua2(String k1,String k2,String v1,String v2){
        DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
        //设置脚本
        String lua = "redis.call('set',KEYS[1],ARGV[1])\n" +
                "redis.call('set',KEYS[2],ARGV[2])\n" +
                "local str1 = redis.call('get',KEYS[1])\n" +
                "local str2 = redis.call('get',KEYS[2])\n" +
                "if str1 == str2 then\n" +
                "return 1\n" +
                "end\n" +
                "return 0";
        redisScript.setScriptText(lua);
        //定义返回类型,注意: 如果没有这个定义,Spring不会返回结果

        redisScript.setResultType(Long.class);
        RedisSerializer stringSerializer = redisTemplate.getStringSerializer();
        //定义key参数
        List<String> keyList = new ArrayList<>();
        keyList.add(k1);
        keyList.add(k2);
        //传递2个参数值,其中第一个序列化器是key的序列化器,第二个序列化器是参数的序列化器
        Object obj = redisTemplate.execute(redisScript, stringSerializer, stringSerializer, keyList,v1,v2);
        Map<String,Object> map = new HashMap<>();
        map.put("success",true);
        map.put("res",obj);
        return map;
    }
}

备注:因为redis默认是连接 localhost:6379,所以没有配置地址和端口号了  (基本常用的redis操作都在这了)

发布了5 篇原创文章 · 获赞 0 · 访问量 118

猜你喜欢

转载自blog.csdn.net/u012939253/article/details/105635101