Spring 采用纯注解使用 RedisTemplate

我在前面的博客中介绍过采用 Jedis 操作 Redis,今天准备介绍 Spring 使用 RedisTemplate 操作 Redis。

Jedis 和 RedisTemplate 两者之间的区别在于:Jedis 是 Redis 官方推荐的面向 Java 操作 Redis 的客户端开发 Jar 包,而 RedisTemplate 是 Spring 框架对 Jedis API 的进行了高度封装(也就是说 RedisTemplate 底层是通过 Jedis 来实现的)。RedisTemplate 能够支持连接池自动管理,使用起来更加方便,实际上在大部分开发场景中,使用 RedisTemplate 会更多一些。

本篇博客的 Demo 基于之前 Jedis 操作 Redis 的 Demo 代码进行简单改造,实现 RedisTemplate 对 Redis 的操作,在博客最后会提供 Demo 源代码。有关 RedisTemplate 的详细内容,请查看 Spring 官网:https://spring.io/projects/spring-data-redis


一、搭建工程

新建一个 maven 项目,导入相关 jar 包,有关 Redis 相关的 jar 包不是最新的 jar 包,其它 jar 包都是最新的,内容如下:

有关具体的 jar 包地址,可以在 https://mvnrepository.com 上进行查询。

<dependencies>
    <!--Spring 相关 jar 包-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.17</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>5.3.17</version>
    </dependency>

    <!--单元测试 jar 包-->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.2</version>
    </dependency>

    <!--操作 Redis 的相关 jar 包-->
    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-redis</artifactId>
        <version>2.0.6.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
        <version>2.9.0</version>
    </dependency>

    <!--
    日志相关 jar 包,主要是上面的 Redis 相关的 jar 包,在运行时需要日志的 jar 包。
    日志的 jar 包也可以不导入,只不过运行过程中控制台总是有红色提示,看着心烦。
    -->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.21</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
</dependencies>

注意:本博客的 Demo 中有关 Redis 相关的 jar 包,不是导入最新的,使用的是经过测试无误的稳定版本。另外 slf4j 和 log4j 相关的日志 jar 包,是 Redis 相关的 jar 所需要的,如果不导入的话,控制台上总是打印出相关的红色提示信息,看着比较心烦。

配置好引用的 jar 包后,打开右侧的 Maven 窗口,刷新一下,这样 Maven 会自动下载所需的 jar 包文件。

搭建好的项目工程整体目录比较简单,具体如下图所示:

image

项目工程结构简单介绍:

com.jobs.config 包下存储的是 Spring 相关的配置文件
resources 目录下存储的是相关的配置文件

test 目录下的文件介绍:
com.jobs.RedisTest 类是专门用来编写 junit 单元测试方法,用来测试操作 Redis 的方法


二、配置相关

resources 目录下 redis.properties 是连接 Redis 的相关配置文件,log4j.properties 是日志相关的配置文件,内容分别如下:

redis.host=localhost
redis.port=6379

# 如果你的 redis 设置了密码的话,可以使用密码配置
# redis.password=123456

redis.maxActive=10
redis.maxIdle=5
redis.minIdle=1
redis.maxWait=3000
log4j.rootLogger=WARN, stdout

# 如果你既要控制台打印日志,也要文件记录日志的话,可以使用下面这行配置
# log4j.rootLogger=WARN, stdout, logfile

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n

log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=target/spring.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n

RedisConfig 类主要实现的功能是读取 Redis 配置信息,创建 RedisTemplate 对象并将其装载到 Spring 容器中:

package com.jobs.config;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisPool;

@PropertySource("redis.properties")
public class RedisConfig {

    @Value("${redis.host}")
    private String host;
    @Value("${redis.port}")
    private Integer port;

    //@Value("${redis.password}")
    //private String password;

    @Value("${redis.maxActive}")
    private Integer maxActive;
    @Value("${redis.minIdle}")
    private Integer minIdle;
    @Value("${redis.maxIdle}")
    private Integer maxIdle;
    @Value("${redis.maxWait}")
    private Integer maxWait;

    //获取RedisTemplate
    @Bean
    public RedisTemplate getRedisTemplate(
            @Autowired RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate redisTemplate = new RedisTemplate();
        redisTemplate.setConnectionFactory(redisConnectionFactory);

        //设置 Redis 生成的key的序列化器,这个很重要
        //RedisTemplate 默认使用 jdk 序列化器,会出现 Redis 的 key 保存成乱码的情况
        //一般情况下 Redis 的 key 都使用字符串,
        //为了保障在任何情况下使用正常,最好使用 StringRedisSerializer 对 key 进行序列化
        RedisSerializer stringSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(stringSerializer);
        redisTemplate.setHashKeySerializer(stringSerializer);
        return redisTemplate;
    }

    //获取 Redis 连接工厂
    @Bean
    public RedisConnectionFactory getRedisConnectionFactory(
            @Autowired RedisStandaloneConfiguration redisStandaloneConfiguration,
            @Autowired GenericObjectPoolConfig genericObjectPoolConfig) {
        JedisClientConfiguration.JedisPoolingClientConfigurationBuilder builder
                = (JedisClientConfiguration.JedisPoolingClientConfigurationBuilder)
                   JedisClientConfiguration.builder();
        builder.poolConfig(genericObjectPoolConfig);
        JedisConnectionFactory jedisConnectionFactory =
                new JedisConnectionFactory(redisStandaloneConfiguration, builder.build());
        return jedisConnectionFactory;
    }

    //获取 Spring 提供的 Redis 连接池信息
    @Bean
    public GenericObjectPoolConfig getGenericObjectPoolConfig() {
        GenericObjectPoolConfig genericObjectPoolConfig = new GenericObjectPoolConfig();
        genericObjectPoolConfig.setMaxTotal(maxActive);
        genericObjectPoolConfig.setMinIdle(minIdle);
        genericObjectPoolConfig.setMaxIdle(maxIdle);
        genericObjectPoolConfig.setMaxWaitMillis(maxWait);
        return genericObjectPoolConfig;
    }

    //获取 Redis 配置对象
    @Bean
    public RedisStandaloneConfiguration getRedisStandaloneConfiguration() {
        RedisStandaloneConfiguration redisStandaloneConfiguration =
            new RedisStandaloneConfiguration();
        redisStandaloneConfiguration.setHostName(host);
        redisStandaloneConfiguration.setPort(port);
        //redisStandaloneConfiguration.setPassword(RedisPassword.of(password));
        return redisStandaloneConfiguration;
    }
}

下面列出 Spring 的启动类配置类 SpringConfig 的详细内容:

package com.jobs.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@ComponentScan("com.jobs")
@Import(RedisConfig.class)
public class SpringConfig {
}

三、使用 RedisTemplate 操作 Redis

我们编写一个单元测试类 RedisTest 来演示 RedisTemplate 操作 Redis 的常见数据类型:

package com.jobs;

import com.jobs.config.SpringConfig;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class RedisTest {

    @Autowired
    private RedisTemplate redisTemplate;

    //测试字符串 String 数据类型
    @Test
    public void testString() {

        //设置
        redisTemplate.opsForValue().set("name", "候胖胖");
        redisTemplate.opsForValue().set("age", "40");

        //获取
        String name = redisTemplate.opsForValue().get("name").toString();
        String age = redisTemplate.opsForValue().get("age").toString();

        System.out.println("name:" + name + ",age:" + age);
    }

    //测试列表 List 数据类型
    @Test
    public void testList() {

        //redis 的 list 可以作为队列使用
        //从列表右边添加数据
        redisTemplate.opsForList().rightPush("fat", "任肥肥");
        redisTemplate.opsForList().rightPush("fat", "侯胖胖");
        redisTemplate.opsForList().rightPush("fat", "李墩墩");

        //获取列表的容量大小
        long fatCount = redisTemplate.opsForList().size("fat");
        System.out.println("列表数量:" + fatCount);

        //从左侧逐个取数据
        for (int i = 0; i < fatCount; i++) {
            String fatMan = redisTemplate.opsForList().leftPop("fat").toString();
            System.out.println(fatMan);
        }
    }

    //测试散列 Hash 数据类型
    @Test
    public void testHash() {

        //redis 的 hash 比较适合存储对象数据
        Map<String, String> user1 = new HashMap<>();
        user1.put("name", "侯胖胖");
        user1.put("age", "40");
        user1.put("kg", "80");

        Map<String, String> user2 = new HashMap<>();
        user2.put("name", "任肥肥");
        user2.put("age", "38");
        user2.put("kg", "90");

        redisTemplate.opsForHash().putAll("user1", user1);
        redisTemplate.opsForHash().putAll("user2", user2);

        //修改第一个用户的年龄
        redisTemplate.opsForHash().put("user1", "age", "45");
        //修改第二个用户的体重
        redisTemplate.opsForHash().put("user2", "kg", "100");

        //获取两个对象的属性值
        Map<String, String> user111 = redisTemplate.opsForHash().entries("user1");
        Map<String, String> user222 = redisTemplate.opsForHash().entries("user2");
        System.out.println(user111);
        System.out.println(user222);
    }

    //测试集合 Set 数据类型
    @Test
    public void testSet() {

        //redis 的 set 跟 java 的 set 使用方式一样,重复的元素只保留一个
        redisTemplate.opsForSet().add("aaa", "a", "b", "c", "x", "y", "z", "a", "x");
        redisTemplate.opsForSet().add("bbb", "b", "c", "d", "e", "f", "y", "b", "e");

        //获取交集
        Set<String> sinter = redisTemplate.opsForSet().intersect("aaa", "bbb");
        System.out.println("交集:" + sinter);

        //获取并集
        Set<String> sunion = redisTemplate.opsForSet().union("aaa", "bbb");
        System.out.println("并集:" + sunion);

        //获取 aaa 相对于 bbb 的差集(存在于 aaa 但不存在与 bbb 的元素)
        Set<String> sdiff = redisTemplate.opsForSet().difference("aaa", "bbb");
        System.out.println("aaa 相对于 bbb 的差集:" + sdiff);
    }

    //测试有序集合 Sorted Set (ZSet) 数据类型
    @Test
    public void testZset() {

        //redis 的 zSet 比较适合做排行榜

        //粉丝投票
        redisTemplate.opsForZSet().add("vote", "侯胖胖", 10d);
        redisTemplate.opsForZSet().add("vote", "李墩墩", 7d);
        redisTemplate.opsForZSet().add("vote", "任肥肥", 6d);
        redisTemplate.opsForZSet().add("vote", "乔豆豆", 12d);
        redisTemplate.opsForZSet().add("vote", "杨重重", 8d);

        //修改任肥肥的投票数
        redisTemplate.opsForZSet().add("vote", "任肥肥", 9d);

        //zSet 默认是按照分值的升序排列
        Set<String> vote1 = redisTemplate.opsForZSet().range("vote", 0, -1);
        System.out.println("投票数量升序排列:" + vote1);

        //获取粉丝投票数量最多的前三个人
        Set<String> vote2 = redisTemplate.opsForZSet().reverseRange("vote", 0, 2);
        System.out.println("投票数量倒序前 3 个人:" + vote2);
    }
}


到此为止,已经快速搭建和演示了 Spring 采用纯注解配置和使用 RedisTemplate 操作 Redis 常见数据类型的 Demo ,整体来说还是非常简单的。更多 RedisTemplate 的使用方式,请参考 Spring 官网。

本博客的 Demo 源代码为:https://files.cnblogs.com/files/blogs/699532/Spring_RedisTemplate.zip



posted @ 2022-04-01 01:08  乔京飞  阅读(9807)  评论(0编辑  收藏  举报