redis数据结构和常用命令

  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。

  

  

猜你喜欢

转载自www.cnblogs.com/hhhshct/p/11567973.html