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操作都在这了)