redis常用数据结构
String 最简单的K_V,value可以是数字或者字符串,使用场景:微博数、普通计数,命令:get set incr(加1) decr(减1) mget(获取多个值),set命令还支持NX(不存在才能设置成功)、EX (失效时间)
List 链表,和java中List一样,使用场景:微博关注粉丝,命令:lpush、rpush、lpop、rpop、lrange(获取所有给定key的值)
Set 和java Set一样,元素不可重复,使用场景:共同关注、命令:sadd、spop、smembers sunion(给定集合的并集)
Sort Set 和Set区别是通过用户额外提供的参数score来排序,使用场景:排行榜,命令 zadd(添加成员或者更新score) 、zrange(根据索引范围集合)、zrem(删除)、zcard(获取成员数)
Hash 和java Hashmap一样,用户存储用户信息,命令 hset hget hgetall
Geo redis3.2版本后支持,地理位置,常用命令:geoadd(添加位置) geodist(获取距离) geohash(获取位置的geohash值) geopos(获取指定位置的坐标) georadius(根据指定位置获取指定范围内的地理位置集合) georadiusbymember(根据指定成员或者指定范围内的地理位置集合)
stream redis5.0后支持,类似于mq
redis在spring中的使用
基于spring和lettuce来实现redis的常用操作
基础配置如下:
spring上下文配置
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:c="http://www.springframework.org/schema/c" xmlns:cache="http://www.springframework.org/schema/cache" xmlns:context="http://www.springframework.org/schema/context" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:lang="http://www.springframework.org/schema/lang" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:p="http://www.springframework.org/schema/p" xmlns:task="http://www.springframework.org/schema/task" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> <!-- Scans the classpath of this application for @Components to deploy as beans --> <context:component-scan base-package="com.jlwj"/> <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <list> <value>classpath:config.properties</value> </list> </property> </bean> <!-- 配置druid数据源 --> <bean name="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <!-- 数据库连接基础信息 --> <property name="url" value="${jdbc_url}"/> <property name="username" value="${jdbc_username}"/> <property name="password" value="${jdbc_password}"/> <!-- 初始化连接大小 --> <property name="initialSize" value="0"/> <!-- 连接池最大使用连接数量 --> <property name="maxActive" value="2000"/> <!-- 连接池最小空闲 --> <property name="minIdle" value="0"/> <!-- 获取连接最大等待时间 --> <property name="maxWait" value="3000"/> <!-- 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。 --> <!-- <property name="poolPreparedStatements" value="true" /> <property name="maxPoolPreparedStatementPerConnectionSize" value="33" /> --> <!-- 验证数据库连接有效性,要求查询语句 --> <property name="validationQuery" value="${validationQuery}"/> <!-- 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 --> <property name="testWhileIdle" value="true"/> <!-- 申请连接时执行validationQuery检测连接是否有效,配置true会降低性能。 --> <property name="testOnBorrow" value="false"/> <!-- 归还连接时执行validationQuery检测连接是否有效,配置true会降低性能 --> <property name="testOnReturn" value="false"/> <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 --> <property name="timeBetweenEvictionRunsMillis" value="60000"/> <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 --> <property name="minEvictableIdleTimeMillis" value="25200000"/> <!-- 对于长时间不使用的连接强制关闭 --> <property name="removeAbandoned" value="true"/> <!-- 关闭超过30分钟的空闲连接,1800秒,也就是30分钟 --> <property name="removeAbandonedTimeout" value="1800"/> <!-- 关闭abanded连接时输出错误日志 --> <property name="logAbandoned" value="true"/> <!-- 监控数据库 --> <!-- <property name="filters" value="mergeStat" /> --> <property name="filters" value="stat"/> </bean> <!-- 使用 spring jdbc 模板 --> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <constructor-arg ref="dataSource"/> </bean> <!-- 此处特意混合一下xml+java两种配置方式 理论上xml和java事是可以相互替代的 --> <bean id="stringRedisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate" p:connection-factory-ref="redisConnectionFactory"> </bean> </beans>
redis配置信息
redis_host=127.0.0.1
redis_port=6379
日志配置
#log for struts and spring
log4j.rootLogger=info,A1
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
#log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%c]-[%p] %m%n
log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss} [%c]-[%p] %m%n
#log4j.logger.org.springframework = debug
log4j.logger.org.springframework.cloud=WARN
log4j.logger.org.springframework.jndi=WARN
log4j.logger.org.springframework.beans=WARN
log4j.logger.org.springframework.core=WARN
log4j.logger.org.springframework.web=WARN
1、基础读写实现及spring整合实现
package com.jlwj.single; import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; import org.springframework.data.redis.cache.RedisCacheConfiguration; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.cache.RedisCacheWriter; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.RedisStandaloneConfiguration; import org.springframework.data.redis.connection.lettuce.LettuceConnection; import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; /** * @author hehang on 2019-07-18 * @description redis配置 */ @Configuration @Profile("single") @EnableCaching public class SingleRedisConfig { @Bean public LettuceConnectionFactory redisConnectionFactory() { System.out.println("单机版本"); return new LettuceConnectionFactory(new RedisStandaloneConfiguration("localhost", 6379)); } @Bean public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate redisTemplate = new RedisTemplate(); redisTemplate.setConnectionFactory(redisConnectionFactory); redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer()); return redisTemplate; } /** * 配置spring cache注解功能 */ @Bean public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) { RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory); RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig(); RedisCacheManager cacheManager = new RedisCacheManager(redisCacheWriter, redisCacheConfiguration); return cacheManager; } }
package com.jlwj.single; import com.jlwj.bean.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Profile; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Service; /** * @author hehang on 2019-07-18 * @description demo service */ @Service @Profile("single") public class SingleDemoService { @Autowired private StringRedisTemplate stringRedisTemplate; // 参数可以是任何对象,默认由JDK序列化 @Autowired private RedisTemplate redisTemplate; /** * 简单的缓存插入功能 */ public void setByCache(String userId, String userInfo) { stringRedisTemplate.opsForValue().set(userId, userInfo); } /** * 对象缓存功能 */ public User findUser(String userId) throws Exception { User user = null; // 1、 判定缓存中是否存在 user = (User) redisTemplate.opsForValue().get(userId); if (user != null) { System.out.println("从缓存中读取到值:" + user); return user; } user = new User(userId, "张三"); System.out.println("从数据库中读取到值:" + user); // 3、 同步存储value到缓存。 redisTemplate.opsForValue().set(userId, user); return user; } }
package com.jlwj.single; import com.jlwj.bean.User; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CachePut; import org.springframework.cache.annotation.Cacheable; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Service; /** * @author hehang on 2019-07-18 * @description zsd */ @Service @Profile("single") public class SpringCacheService { @Cacheable(cacheManager = "cacheManager", value = "cache-1", key = "#userId") public User findUserById(String userId) throws Exception { // 读取数据库 User user = new User(userId, "张三"); System.out.println("从数据库中读取到数据:" + user); return user; } @CacheEvict(cacheManager = "cacheManager", value = "cache-1", key = "#userId") public void deleteUserById(String userId) throws Exception { System.out.println("用户从数据库删除成功,请检查缓存是否清除~~" + userId); } // 如果数据库更新成功,更新redis缓存 @CachePut(cacheManager = "cacheManager", value = "cache-1", key = "#user.userId", unless = "#result == null") public User updateUser(User user) throws Exception { // 读取数据库 System.out.println("数据库进行了更新,检查缓存是否一致"); return user; // 返回最新内容,代表更新成功 } }
package com.jlwj.single; import com.jlwj.bean.User; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Profile; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.junit4.SpringRunner; /** * @author hehang on 2019-07-18 * @description sdf */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") @ActiveProfiles("single") public class SingleTest { @Autowired private SingleDemoService singleDemoService; @Autowired private SpringCacheService springCacheService; @Test public void cacheTest() throws Exception { User user = singleDemoService.findUser("junlin"); System.out.println(user); } @Test public void springCacheTest() throws Exception { User user = springCacheService.findUserById("zhangsan"); System.out.println(user); } @Test public void springCacheTest1() throws Exception { springCacheService.deleteUserById("zhangsan"); ; } @Test public void springCacheTest2() throws Exception { User user = new User("zhangsan", "李四"); User result = springCacheService.updateUser(user); System.out.println(result); } }
2、pipline批量处理,用于项目启动后加载大量缓存信息
package com.jlwj.pipeline; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.RedisStandaloneConfiguration; import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; /** * @author hehang on 2019-07-18 * @description asd */ @Configuration @Profile("pipeline") public class PipelineRedisConfig { @Bean public LettuceConnectionFactory redisConnectionFactory() { System.out.println("使用单机版本"); return new LettuceConnectionFactory(new RedisStandaloneConfiguration("localhost", 6379)); } @Bean public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate redisTemplate = new RedisTemplate(); redisTemplate.setConnectionFactory(redisConnectionFactory); // 可以配置对象的转换规则,比如使用json格式对object进行存储。 // Object --> 序列化 --> 二进制流 --> redis-server存储 redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer()); return redisTemplate; } }
package com.jlwj.pipeline; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataAccessException; import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.core.RedisCallback; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /** * @author hehang on 2019-07-18 * @description asd */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") @ActiveProfiles("pipeline") public class PipelineTest { @Autowired RedisTemplate redisTemplate; @Test public void test1() throws InterruptedException { // 普通模式和pipeline模式 long time = System.currentTimeMillis(); for (int i = 0; i < 10000; i++) { redisTemplate.opsForList().leftPush("queue_1", i); } System.out.println("操作完毕:" + redisTemplate.opsForList().size("queue_1")); System.out.println("普通模式一万次操作耗时:" + (System.currentTimeMillis() - time)); time = System.currentTimeMillis(); redisTemplate.executePipelined(new RedisCallback<String>() { @Override public String doInRedis(RedisConnection connection) throws DataAccessException { for (int i = 0; i < 10000; i++) { connection.lPush("queue_2".getBytes(), String.valueOf(i).getBytes()); } return null; } }); System.out.println("操作完毕:" + redisTemplate.opsForList().size("queue_2")); System.out.println("pipeline一万次操作耗时:" + (System.currentTimeMillis() - time)); } }
3、地理位置信息
package com.jlwj.geo; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.RedisStandaloneConfiguration; import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; /** * @author hehang on 2019-07-18 * @description asd */ @Configuration @Profile("geo") public class GeoRedisConfig { @Bean public LettuceConnectionFactory redisConnectionFactory() { System.out.println("使用单机版本"); return new LettuceConnectionFactory(new RedisStandaloneConfiguration("localhost", 6379)); } @Bean public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate redisTemplate = new RedisTemplate(); redisTemplate.setConnectionFactory(redisConnectionFactory); // 可以配置对象的转换规则,比如使用json格式对object进行存储。 // Object --> 序列化 --> 二进制流 --> redis-server存储 redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer()); return redisTemplate; } }
package com.jlwj.geo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Profile; import org.springframework.data.geo.Circle; import org.springframework.data.geo.Distance; import org.springframework.data.geo.GeoResults; import org.springframework.data.geo.Point; import org.springframework.data.redis.connection.RedisGeoCommands; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; /** * @author hehang on 2019-07-18 * @description asd */ @Service @Profile("geo") public class GeoExampleService { @Autowired private RedisTemplate redisTemplate; public void addGeoInfo(Point point, String userId) { redisTemplate.opsForGeo().add("user_geo", new RedisGeoCommands.GeoLocation(userId, point)); } public GeoResults<RedisGeoCommands.GeoLocation> near(Point point) { Distance distance = new Distance(100, RedisGeoCommands.DistanceUnit.METERS); Circle circle = new Circle(point, distance); RedisGeoCommands.GeoRadiusCommandArgs geoRadiusCommandArgs = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().limit(5); GeoResults<RedisGeoCommands.GeoLocation> geoResults = redisTemplate.opsForGeo().radius("user_geo", circle, geoRadiusCommandArgs); return geoResults; } }
package com.jlwj.geo; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.geo.GeoResult; import org.springframework.data.geo.GeoResults; import org.springframework.data.geo.Point; import org.springframework.data.redis.connection.ReactiveGeoCommands; import org.springframework.data.redis.connection.RedisGeoCommands; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /** * @author hehang on 2019-07-18 * @description sd */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") @ActiveProfiles("geo") public class GeoTest { @Autowired private GeoExampleService geoExampleService; @Test public void addTest() { geoExampleService.addGeoInfo(new Point(116.405285, 39.904989), "张三"); geoExampleService.addGeoInfo(new Point(116.405265, 39.904969), "里斯"); geoExampleService.addGeoInfo(new Point(116.405315, 39.904999), "王五"); GeoResults<RedisGeoCommands.GeoLocation> geoResults = geoExampleService.near(new Point(116.405315, 39.904999)); for (GeoResult<RedisGeoCommands.GeoLocation> geoResult : geoResults) { RedisGeoCommands.GeoLocation content = geoResult.getContent(); System.out.println(content.getName() + ":" + geoResult.getDistance().getValue()); } } }
4、发布订阅
package com.jlwj.pubsub; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.RedisStandaloneConfiguration; import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; @Configuration @Profile("pubsub") class PubsubRedisAppConfig { /** * 用于测试的通道名称 */ public final static String TEST_CHANNEL_NAME = "sms_send"; @Bean public LettuceConnectionFactory redisConnectionFactory() { System.out.println("使用单机版本"); return new LettuceConnectionFactory(new RedisStandaloneConfiguration("localhost", 6379)); } @Bean public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate redisTemplate = new RedisTemplate(); redisTemplate.setConnectionFactory(redisConnectionFactory); // 可以配置对象的转换规则,比如使用json格式对object进行存储。 // Object --> 序列化 --> 二进制流 --> redis-server存储。 redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer()); return redisTemplate; } }
package com.jlwj.pubsub; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Profile; import org.springframework.dao.DataAccessException; import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.core.RedisCallback; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; /** * @author hehang on 2019-07-18 * @description asd */ @Component @Profile("pubsub") public class SmsChannelListener { @Autowired private RedisTemplate redisTemplate; @PostConstruct public void listening() { redisTemplate.execute(new RedisCallback() { @Override public Object doInRedis(RedisConnection redisConnection) throws DataAccessException { redisConnection.subscribe((message, pattern) -> { System.out.println("收到消息:" + message); }, PubsubRedisAppConfig.TEST_CHANNEL_NAME.getBytes()); return null; } }); } }
package com.jlwj.pubsub; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; import org.springframework.data.redis.connection.Message; import org.springframework.data.redis.connection.MessageListener; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.listener.ChannelTopic; import org.springframework.data.redis.listener.RedisMessageListenerContainer; import java.util.Arrays; /** * @author hehang on 2019-07-18 * @description asd */ @Profile("pubsub") @Configuration public class SmsChannelListenerBySpring { @Bean public RedisMessageListenerContainer smsMessageListener(RedisConnectionFactory redisConnectionFactory) { RedisMessageListenerContainer redisMessageListenerContainer = new RedisMessageListenerContainer(); redisMessageListenerContainer.setConnectionFactory(redisConnectionFactory); SmsListener smsListener = new SmsListener(); redisMessageListenerContainer.addMessageListener(smsListener, Arrays.asList(new ChannelTopic(PubsubRedisAppConfig.TEST_CHANNEL_NAME))); return redisMessageListenerContainer; } class SmsListener implements MessageListener { @Override public void onMessage(Message message, byte[] bytes) { System.out.println("收到的消息:" + message); } } }
package com.jlwj.pubsub; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataAccessException; import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.core.RedisCallback; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /** * @author hehang on 2019-07-18 * @description asd */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") @ActiveProfiles("pubsub") // 设置profile public class PubSubTests { @Autowired RedisTemplate redisTemplate; @Test public void test1() throws InterruptedException { System.out.println("开始测试发布订阅机制,5秒后发布一条消息"); Thread.sleep(5000L); redisTemplate.execute(new RedisCallback<Long>() { @Override public Long doInRedis(RedisConnection connection) throws DataAccessException { // 发送通知 Long received = connection.publish(PubsubRedisAppConfig.TEST_CHANNEL_NAME.getBytes(), "{手机号码10086~短信内容~~}".getBytes()); return received; } }); } // 当key被删除,或者key过期之后,也会有通知,需要redis server开启相关支持,具体配置及使用见https://redis.io/topics/notifications @Test public void test2() throws InterruptedException { redisTemplate.execute(new RedisCallback<Long>() { @Override public Long doInRedis(RedisConnection connection) throws DataAccessException { connection.subscribe((message, pattern) -> { System.out.println("收到消息,使用redisTemplate收到的:" + message); }, "__keyevent@0__:del".getBytes()); return null; } }); redisTemplate.opsForValue().set("hkkkk", "张三"); Thread.sleep(1000L); redisTemplate.delete("hkkkk"); Thread.sleep(1000L); } }
5、stream,类似于MQ,目前使用较少,具体可以参考redis官网中commands。