Spring Boot:使用Redis存儲技術


綜合概述

Redis是一個開源免費的高性能key-value數據庫,讀取速度達110000次/s,寫入速度達81000次/s。Redis支持豐富的數據類型,如Lists, Hashes, Sets 及 Ordered Sets 數據類型。Redis的所有操作都是原子性的,要么成功執行要么失敗完全不執行。另外還可以通過MULTI和EXEC指令包起來支持事務。此外,Redis還具備豐富的特性 ,比如支持發布/訂閱(publish/subscribe)模式,可以充當簡單的消息中間件,還支持通知, key過期設置主從復制等等特性。

Redis主要以下三個特點:

1.支持數據的持久化,可以將內存中的數據保存在磁盤中,重啟的時候可以再次加載進行使用。

2.支持豐富的數據類型,除了支持簡單的key-value類型,同時還提供list,set,zset,hash等數據結構的存儲。

3.支持數據的備份,即主從(master-slave)模式模式的數據備份。

接下來,我們就用一個簡單的案例來說明在Spring Boot中如何使用Redis技術。

實現案例

首先,需要安裝Redis,教程很多,這里不再贅述。可以參考:Redis安裝教程

生成項目模板

為方便我們初始化項目,Spring Boot給我們提供一個項目模板生成網站。

1.  打開瀏覽器,訪問:https://start.spring.io/

2.  根據頁面提示,選擇構建工具,開發語言,項目信息等。

3.  點擊 Generate the project,生成項目模板,生成之后會將壓縮包下載到本地。

4.  使用IDE導入項目,我這里使用Eclipse,通過導入Maven項目的方式導入。

添加相關依賴

清理掉不需要的測試類及測試依賴,添加 Redis相關依賴。

<!-- spring boot redis -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- lettuce pool -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>

Spring Boot框架中已經集成了redis,在1.x.x的版本中默認使用jedis客戶端,而在2.x.x版本中默認使用的lettuce客戶端。

兩種客戶端的區別如下:

  • Jedis和Lettuce都是Redis Client
  • Jedis 是直連模式,在多個線程間共享一個 Jedis 實例時是線程不安全的,
  • 如果想要在多線程環境下使用 Jedis,需要使用連接池,
  • 每個線程都去拿自己的 Jedis 實例,當連接數量增多時,物理連接成本就較高了。
  • Lettuce的連接是基於Netty的,連接實例可以在多個線程間共享,
  • 所以,一個多線程的應用可以使用同一個連接實例,而不用擔心並發線程的數量。
  • 當然這個也是可伸縮的設計,一個連接實例不夠的情況也可以按需增加連接實例。
  • 通過異步的方式可以讓我們更好的利用系統資源,而不用浪費線程等待網絡或磁盤I/O。
  • Lettuce 是基於 netty 的,netty 是一個多線程、事件驅動的 I/O 框架,
  • 所以 Lettuce 可以幫助我們充分利用異步的優勢。

我的項目是使用的是Spring Boot 2.1.5.RELEASE,所以采用lettuce來進行配置。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.louis.springboot</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <!-- web -->
        <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
         </dependency>
        <!-- swagger -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>
        <!-- spring boot redis -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!-- lettuce pool -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

添加相關配置

1.添加swagger 配置

添加一個swagger 配置類,在工程下新建 config 包並添加一個 SwaggerConfig 配置類。

SwaggerConfig.java

package com.louis.springboot.demo.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
public class SwaggerConfig {

    @Bean
    public Docket createRestApi(){
        return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.any())
                .paths(PathSelectors.any()).build();
    }

    private ApiInfo apiInfo(){
        return new ApiInfoBuilder()
                .title("Swagger API Doc")
                .description("This is a restful api document of Swagger.")
                .version("1.0")
                .build();
    }

}

2.修改application.properties文件名為application.yml,在其中添加Redis配置信息。

application.yml

spring:
  redis:
    database: 0  # Redis數據庫索引(默認為0)
    host: localhost # Redis服務器地址
    port: 6379  # Redis服務器連接端口
    password:   # Redis服務器連接密碼(默認為空)
    lettuce:
      pool:
       max-active: 8  # 連接池最大連接數(使用負值表示沒有限制) 默認 8
       max-wait: -1   # 連接池最大阻塞等待時間(使用負值表示沒有限制) 默認 -1
       max-idle: 8    # 連接池中的最大空閑連接 默認 8
       min-idle: 0    # 連接池中的最小空閑連接 默認 0

3.添加一個Redis配置類,使用@EnableCaching注解來開啟緩存。

RedisConfig.java

package com.louis.springboot.demo.config;

import java.lang.reflect.Method;

import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport{
    
    @Bean
    public KeyGenerator keyGenerator() {
        return new KeyGenerator() {
            @Override
            public Object generate(Object target, Method method, Object... params) {
                StringBuilder sb = new StringBuilder();
                sb.append(target.getClass().getName());
                sb.append(method.getName());
                for (Object obj : params) {
                    sb.append(obj.toString());
                }
                return sb.toString();
            }
        };
    }
}

編寫業務邏輯

編寫一個簡單的用戶實體類,包含用戶名和密碼。

User.java

package com.louis.springboot.demo.model;

import java.io.Serializable;

public class User implements Serializable {

    private static final long serialVersionUID = 1L;
    
    private String username;
    private String password;
    
    public User(String username, String password) {
        super();
        this.username = username;
        this.password = password;
    }
    
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    
    @Override
    public String toString() {
        return "{username:" + getUsername() + ", password:" +getPassword() + "}";
    }
}

編寫一個業務控制器,分別編寫測試字符串和對象的存取接口,另外還通過@Cacheable(value="user-key")注解給方法開啟緩存,這樣就可以緩存方法返回的結果,只有當緩存不存在的時候采用執行方法返回新的用戶對象。

RedisController.java

package com.louis.springboot.demo.controller;

import java.util.concurrent.TimeUnit;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import com.louis.springboot.demo.model.User;

@RestController
public class RedisController {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private RedisTemplate redisTemplate;

    @GetMapping("/testString")
    public String testString()  {
        stringRedisTemplate.opsForValue().set("name", "louis");
        String name = stringRedisTemplate.opsForValue().get("name");
        return "the value of key 'name' is : " + name ;
    }
    
    @GetMapping("/testObject")
    public String testObject()  {
        StringBuilder result = new StringBuilder();
        User user = new User("louis", "123");
        ValueOperations<String, User> operations = redisTemplate.opsForValue();
        operations.set("sys.user", user);
        operations.set("sys.user.timeout", user, 1, TimeUnit.SECONDS);    // 設置1秒后過期
        result.append("過期前:").append("\n");
        result.append("sys.user=" + operations.get("sys.user")).append("\n");
        result.append("sys.user.timeout=" + operations.get("sys.user.timeout"));
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        result.append("\n").append("過期后:").append("\n");
        result.append("sys.user=" + operations.get("sys.user")).append("\n");
        result.append("sys.user.timeout=" + operations.get("sys.user.timeout"));
        return result.toString();
    }
    
    @GetMapping("/getUser")
    @Cacheable(value="user-key")
    public User getUser() {
        User user = new User("louis", "123");
        System.out.println("用戶對象緩存不存在,返回一個新的用戶對象。");
        return user;
    }
}

編譯運行測試

1.  右鍵項目 -> Run as -> Maven install,開始執行Maven構建,第一次會下載Maven依賴,可能需要點時間,如果出現如下信息,就說明項目編譯打包成功了。

 

2.  右鍵文件 DemoApplication.java -> Run as -> Java Application,開始啟動應用,當出現如下信息的時候,就說明應用啟動成功了,默認啟動端口是8080。

 

3.  打開瀏覽器,訪問:http://localhost:8080/swagger-ui.html,進入swagger接口文檔界面。

4.調用testString接口,如果能出現如下圖所示結果就說明成功了

5.調用testObject接口,如果能出現如下圖所示結果就說明成功了。

6.調用getUser接口,此時因為是第一次調用此方法,所以沒有key值為“user-key”的緩存,所以會執行方法並將返回結果進行緩存。在執行getUser方法的時候控制台輸出了我們添加的提示信息如下。

用戶對象緩存不存在,返回一個新的用戶對象。

7.然后再次調用getUser接口,發現getUser沒有再次被執行,控制台也沒有輸出上一步的提示信息,那是因為在方法調用之前,應用從key值為“user-key”的緩存中獲取成功,所以並不需要繼續執行getUser方法的內容了。

 

參考資料

官方網站:https://redis.io/documentation

百度百科:https://baike.baidu.com/item/Redis/6549233?fr=aladdin

菜鳥教程:https://www.runoob.com/redis/redis-tutorial.html

相關導航

Spring Boot 系列教程目錄導航

Spring Boot:快速入門教程

Spring Boot:整合Swagger文檔

Spring Boot:整合MyBatis框架

Spring Boot:實現MyBatis分頁

源碼下載

碼雲:https://gitee.com/liuge1988/spring-boot-demo.git


作者:朝雨憶輕塵
出處:https://www.cnblogs.com/xifengxiaoma/ 
版權所有,歡迎轉載,轉載請注明原文作者及出處。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM