第14课:Spring

第14课:Spring Boot 中集成 Redis

Redis 介绍

Redis 是一种非关系型数据库(NoSQL),NoSQL 以 Key-Value 形式存储,与传统关系型数据库不一样,不一定遵循传统数据库的基本要求,比如说 SQL 标准、ACID 属性、表结构等等。非关系型、分布式、开源、水平可扩展,是这类数据库的主要特点。NoSQL 使用场景主要有对数据高并发读写、对海量数据的高效率存储和访问、对数据的高可扩展性和高可用性等等。

Redis 的 Key 可以是字符串、哈希、链表、集合和有序集合。Value 类型很多,包括 String、List、Set、ZSet 等。这些数据类型都支持 Push/Pop、Add/Remove、取交集和并集以及更多更丰富的操作,Redis 也支持各种不同方式的排序。为了保证效率,数据都缓存在内存中,它也可以周期性的把要更新的数据写入磁盘或者把修改操作写入追加的记录文件中。使用 Redis 有哪些好处呢?举个比较简单的例子,看下图:

Redis使用场景

Redis 集群中的数据和 MySQL 保持同步。获取数据时,会优先从 Redis 中取,如若这时 Redis 挂了,则可从 MySQL 中获取,这样整个网站不会因 Redis 故障而崩溃。关于 Redis 的更多介绍及使用场景,大家可以谷歌和百度了解,这里就不赘述了。

Redis 安装

本课程中,我们选择在 VMvare 虚拟机中安装 Redis (CentOS 7)。如果您有自己的阿里云服务器,也可以在阿里云中安装。只要能 Ping 的通云主机或者虚拟机的 IP,并在虚拟机或者云主机中放行对应的端口(或者关掉防火墙)即可访问 Redis。

下面来介绍一下 Redis 的安装过程。

1. 安装 gcc 编译。

安装 Redis 时需要编译,我们要事先安装好 gcc 编译,命名如下所示。阿里云主机已经默认安装了 gcc,就无需这一步。

yum install gcc-c++

2. 下载 Redis。

有两种方式下载安装包,一种是到官网上下载,并将安装包拷贝到 Centos 中,另一种方法是直接使用 wget 下载:

wget http://download.redis.io/releases/redis-3.2.8.tar.gz

如果没有安装过 wget,可以通过如下命令安装:

yum install wget

3. 解压安装。

解压安装包:

tar –vzxf redis-3.2.8.tar.gz

将解压的文件夹 redis-3.2.8 放到 /usr/local/ 目录下(一般安装软件都会放在 /usr/local 下)。之后进入 /usr/local/redis-3.2.8/ 文件夹下,执行 make 命令即可完成安装。

如果 make 命令执行失败,可尝试如下命令:

make MALLOC=libc
make install

4. 修改配置文件。

安装成功之后,需要修改一下配置文件,包括允许接入的 IP、允许后台执行、设置密码等等。

打开 Redis 配置文件:vi redis.conf,在命令模式下输入 /bind 查找 bind 配置,按 n 查找下一个,找到配置后,将 bind 配置成 0.0.0.0,允许任意服务器访问 Redis,即:

bind 0.0.0.0

使用同样的方法,将 daemonize 改成 yes (默认为 no),允许 Redis 在后台执行。

将 requirepass 注释打开,并设置密码为 123456(密码自己设置)。

5. 启动 Redis。

Redis-3.2.8 目录下,指定刚刚修改好的配置文件 redis.conf 来启动 Redis:

redis-server ./redis.conf

再启动 Redis 客户端:

redis-cli

由于我们设置了密码,在启动客户端之后,输入 auth 123456 即可登录进入客户端。

然后我们测试一下,往 Redis 中插入一条数据:

set name CSDN

之后获取 name:

get name

如果正常获取到 CSDN,则说明没有问题。

Spring Boot 集成 Redis

依赖导入

Spring Boot 集成 Redis 很方便,只需要导入一个 Redis 的 starter 依赖即可。如下:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--阿里巴巴fastjson -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.35</version>
</dependency>

这里,我们也引入了阿里巴巴推出的 Fastjson。后面要存储实例,该工具可以很方便地将实体转换成 JSON 字符串进行存储。

Redis 配置

导入依赖之后,我们在 application.yml 文件里配置 Redis:

server:
  port: 8080
spring:
  #Redis相关配置
  redis:
    database: 5
    # 配置Redis的主机地址,需要修改成自己的
    host: 192.168.48.190
    port: 6379
    password: 123456
    timeout: 5000
    jedis:
      pool:
        # 连接池中的最大空闲连接,默认值也是8。
        max-idle: 500
        # 连接池中的最小空闲连接,默认值也是0。
        min-idle: 50
        # 如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted(耗尽)
        max-active: 1000
        # 等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。如果超过等待时间,则直接抛出JedisConnectionException
        max-wait: 2000

常用 API 介绍

Spring Boot 对 Redis 的支持已经非常完善,丰富的 API 足够我们日常的开发,这里我介绍几个最常用的供大家学习,其他 API 希望大家自己多学习,多研究,用到会去查即可。

目前有两个 Redis 模板:RedisTemplate 和 StringRedisTemplate。这里不推荐使用 RedisTemplate,因为 RedisTemplate 提供的是操作对象,我们通常以 JSON 格式存储该对象,存储时,会使用 Redis 默认的内部序列化器,易导致存储内容出现乱码。当然了,我们可以自定义序列化,但比较麻烦。所以多会使用 StringRedisTemplate 模板。StringRedisTemplate 为我们提供了字符串操作,将实体类转换成 JSON 字符串进行存储,等取出来后,再将其转换成相应的对象,这也就是我在上面导入了阿里巴巴 Fastjson 的原因。

Redis:String 类型

新建一个 RedisService,注入 StringRedisTemplate,使用 stringRedisTemplate.opsForValue() 可以获取 ValueOperations<String, String> 对象,通过该对象即可读写 Redis 数据库。如下:

public class RedisService {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    /**
     * set redis: string类型
     * @param key key
     * @param value value
     */
    public void setString(String key, String value){
        ValueOperations<String, String> valueOperations = stringRedisTemplate.opsForValue();
        valueOperations.set(key, value);
    }

    /**
     * get redis: string类型
     * @param key key
     * @return
     */
    public String getString(String key){
        return stringRedisTemplate.opsForValue().get(key);
    }

该对象操作的是 String,我们也可以存实体类,只需要将实体类转换成 JSON 字符串即可。下面来测试一下:

@RunWith(SpringRunner.class)
@SpringBootTest
public class Course14ApplicationTests {

    private static final Logger logger = LoggerFactory.getLogger(Course14ApplicationTests.class);

    @Resource
    private RedisService redisService;

    @Test
    public void contextLoads() {
        //测试Redis的string类型
        redisService.setString("weichat","程序员私房菜");
        logger.info("我的微信公众号为:{}", redisService.getString("weichat"));

        // 如果是个实体,我们可以使用json工具转成json字符串,
        User user = new User("CSDN", "123456");
        redisService.setString("userInfo", JSON.toJSONString(user));
        logger.info("用户信息:{}", redisService.getString("userInfo"));
    }
}

先启动 Redis,然后运行这个测试用例,观察控制台打印的日志如下:

我的微信公众号为:程序员私房菜
用户信息:{"password":"123456","username":"CSDN"}
Redis:Hash 类型

Hash 类型的原理其实和 String 一样,但 Hash 有两个 Key,使用 stringRedisTemplate.opsForHash() 可以获取 HashOperations<String, Object, Object> 对象。比如我们要存储订单信息,所有订单信息都放在 order 下,针对不同用户的订单实体,可以通过用户的 id 来区分,这就相当于两个 Key 了。

@Service
public class RedisService {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    /**
     * set redis: hash类型
     * @param key key
     * @param filedKey filedkey
     * @param value value
     */
    public void setHash(String key, String filedKey, String value){
        HashOperations<String, Object, Object> hashOperations = stringRedisTemplate.opsForHash();
        hashOperations.put(key,filedKey, value);
    }

    /**
     * get redis: hash类型
     * @param key key
     * @param filedkey filedkey
     * @return
     */
    public String getHash(String key, String filedkey){
        return (String) stringRedisTemplate.opsForHash().get(key, filedkey);
    }
}

可以看出,Hash 和 String 没啥两样,只不过多了个参数,Spring Boot 中操作 Redis 非常简单方便。来测试一下:

@SpringBootTest
public class Course14ApplicationTests {

    private static final Logger logger = LoggerFactory.getLogger(Course14ApplicationTests.class);

    @Resource
    private RedisService redisService;

    @Test
    public void contextLoads() {
        //测试Redis的hash类型
        redisService.setHash("user", "name", JSON.toJSONString(user));
        logger.info("用户姓名:{}", redisService.getHash("user","name"));
    }
}
Redis:list 类型

使用 stringRedisTemplate.opsForList() 可以获取 ListOperations<String, String> listOperations Redis 列表对象,该列表是个简单的字符串列表,可以支持从左侧添加,也可以支持从右侧添加,一个列表最多包含 $2^{32} -1$ 个元素。

@Service
public class RedisService {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    /**
     * set redis:list类型
     * @param key key
     * @param value value
     * @return
     */
    public long setList(String key, String value){
        ListOperations<String, String> listOperations = stringRedisTemplate.opsForList();
        return listOperations.leftPush(key, value);
    }

    /**
     * get redis:list类型
     * @param key key
     * @param start start
     * @param end end
     * @return
     */
    public List<String> getList(String key, long start, long end){
        return stringRedisTemplate.opsForList().range(key, start, end);
    }
}

可以看出,这些 API 具有相同的形式,方便记忆和使用。更多的 API 细节我就不展开了,大家可以自己看文档。其实,根据参数和返回值,也可判断出这些 API 用途。我们来测试一下:

@RunWith(SpringRunner.class)
@SpringBootTest
public class Course14ApplicationTests {

    private static final Logger logger = LoggerFactory.getLogger(Course14ApplicationTests.class);

    @Resource
    private RedisService redisService;

    @Test
    public void contextLoads() {
        //测试redis的list类型
        redisService.setList("list", "football");
        redisService.setList("list", "basketball");
        List<String> valList = redisService.getList("list",0,-1);
        for(String value :valList){
            logger.info("list中有:{}", value);
        }
    }
}

总结

本节主要介绍了 Redis 的使用场景、安装过程,以及 Spring Boot 中集成 Redis 的详细步骤。在实际项目中,通常都将 Redis 作为缓存,在查询数据库的时候,会先从 Redis 中查找,如果有信息,则从 Redis 中取;如果没有,则从数据库中查,并且同步到 Redis 中,这样下次再访问 Redis 时就有数据了。更新和删除也是如此,都需要同步到 Redis。Redis 在高并发场景下运用得较多。

课程源代码下载地址:

戳我下载

上一篇
下一篇
目录