SpringBoot+Redis做爲二級緩存整合的基本Demo

1、Redis簡介

一、概述

  Redis 是一個高性能的key-value數據庫。 redis的出現,很大程度補償了memcached這類key/value存儲的不足,在部 分場合能夠對關係數據庫起到很好的補充做用。它提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby,Erlang等客戶端,使用很方便。java

二、優勢

(1)數據操做全在內存,讀寫性能強。
(2)數據結構豐富,支持string,hash,list,set及zset(sorted set)。
(3)支持主從複製,以及數據持久化等mysql

2、Redis的搭建

一、安裝

按順序執行以下命令:web

$ wget http://download.redis.io/releases/redis-5.0.4.tar.gz
$ tar xzf redis-5.0.4.tar.gz
$ cd redis-5.0.4
$ make
$ make install
複製代碼

二、測試

開啓服務redis

$ redis-server
複製代碼

啓動客戶機交互測試spring

$ redis-cli -p 6379
127.0.0.1:6379> set k1 k2
OK
127.0.0.1:6379> get k1
"k2"
127.0.0.1:6379> 

複製代碼

3、基本環境配置

這裏使用MyBatis做爲持久層框架,使用MySql數據庫。sql

一、POM依賴

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.0.1</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
複製代碼

二、YML配置文件

server:
 port: 80
spring:
 http:
 encoding:
 charset: UTF-8
 cache:
 type: redis
 redis:
    #redis服務器地址
 host: 192.168.78.128
    #設置端口號,默認6379
 port: 6379
 datasource:
 driver-class-name: com.mysql.jdbc.Driver
 username: root
 password: 123456
 url: jdbc:mysql://localhost:3306/test
#控制檯查看SQL執行情況
logging:
 level:
   com.yurui.rediscache: debug
複製代碼

三、測試鏈接

@RunWith(SpringRunner.class)
@SpringBootTest
public class RediscacheApplicationTests {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    
    @Test
    public void contextLoads() {
        stringRedisTemplate.opsForValue().set("k1","v1");
        System.out.println(stringRedisTemplate.opsForValue().get("k1"));
    }
}
複製代碼

測試成功效果: 數據庫

測試成功
測試失敗的可能緣由:

一、Linux防火牆沒設置好
二、啓動服務器前配置文件內沒有把bind 127.0.0.1註釋掉
三、配置文件中沒把protected-mode yes改成no緩存

4、三個基本的緩存標籤

一、@Cacheable

  @Cacheable能夠標記在一個方法上,也能夠標記在一個類上。當標記在一個方法上時表示該方法是支持緩存的,當標記在一個類上時則表示該類全部的方法都是支持緩存的。對於一個支持緩存的方法,Spring會在其被調用後將其返回值緩存起來,以保證下次利用一樣的參數來執行該方法時能夠直接從緩存中獲取結果,而不須要再次執行該方法。bash

二、@CachePut

  @CachePut能夠聲明一個方法支持緩存功能。與@Cacheable不一樣的是使用@CachePut標註的方法在執行前不會去檢查緩存中是否存在以前執行過的結果,而是每次都會執行該方法,並將執行結果以鍵值對的形式存入指定的緩存中。服務器

三、@CacheEvict

  @CacheEvict是用來標註在須要清除緩存元素的方法或類上的。當標記在一個類上時表示其中全部的方法的執行都會觸發緩存的清除操做。@CacheEvict能夠指定的屬性有value、key、condition、allEntries和beforeInvocation。

三者共有屬性:

  • value(cacheName)
    @Cacheable@CachePut標註時表示生成的緩存的名稱,@CacheEvict標註時表示將要清空的緩存的名稱。

  • key
    在同一名稱(類別)下的緩存,須要惟一的key值來標識惟一的緩存,如未指定則會使用默認策略生成的key;

  • condition
    表示緩存操做發生的條件

@CacheEvict的allEntries和beforeInvocation屬性

  • allEntries
      allEntries是boolean類型,表示是否須要清除同一名稱的緩存中的全部元素。默認爲false,表示不須要。當指定了allEntries爲true時,Spring Cache將忽略指定的key,清除全部同一名稱的緩存。
  • beforeInvocation
      清除操做默認是在對應方法成功執行以後觸發的,即方法若是由於拋出異常而未能成功返回時也不會觸發清除操做。使用beforeInvocation能夠改變觸發清除操做的時間,當咱們指定該屬性值爲true時,Spring會在調用該方法以前清除緩存中的指定元素。

實例

@Cacheable(cacheNames = "User", key = "#userId")
    @GetMapping("/testCacheable/{userId}")
    public User testCacheable(@PathVariable("userId") Integer userId) {
        // 方法體
    }
複製代碼

訪問/testCacheable/{userId}時會將返回的User進行緩存,其對應名稱爲"User",所生成的key爲傳入進來的userId。

5、基本的Demo

項目結構

項目結構

數據表結構

數據表結構

PO:

@Component
public class User implements Serializable {
    private int userId;
    private String username;
    // setters,getters,toString()方法已被省略
}
複製代碼

因爲業務邏輯簡單,取消了Service層

Mapper:

@Mapper
public interface UserMapper {
    @Insert("insert into user(userId,username) values(#{userId},#{username})")
    int userInsert(User user);

    @Select("select * from user where userId=#{userId}")
    User userQuery(int userId);
}
複製代碼

Controller:

@RestController
public class UserController {

    @Autowired
    private UserMapper userMapper;

    @PostMapping("user")
    public String userAdd(User user) {
        return userMapper.userInsert(user) != 0 ? "success" : "fail";
    }

    // 測試Cacheable註解
    @Cacheable(cacheNames = "User", key = "#userId")
    @GetMapping("/testCacheable/{userId}")
    public User testCacheable(@PathVariable("userId") Integer userId) {
        return userMapper.userQuery(userId);
    }

    // 測試CachePut註解
    @CachePut(cacheNames = "User", key = "#userId") //緩存名字爲"User","userId"做爲key
    @GetMapping("/testCachePut/{userId}")
    public User testCachePut(@PathVariable("userId") Integer userId) {
        return userMapper.userQuery(userId);
    }

    // 測試CacheEvict註解清空指定用戶緩存
    @CacheEvict(cacheNames = "User", key = "#userId")
    @GetMapping("/testCacheEvict/{userId}")
    public String testCacheEvict(@PathVariable("userId") Integer userId) {
        return "cache for " + userId + " has been flushed";
    }

    // 測試CacheEvict註解的allEntries屬性清空全部用戶緩存
    @CacheEvict(cacheNames = "User", allEntries = true)
    @GetMapping("/testAllEntries")
    public String testAllEntries() {
        return "All caches have been flushed";
    }
}
複製代碼

主類

@SpringBootApplication
@EnableCaching                          // 開啓緩存註解
public class RediscacheApplication {

    public static void main(String[] args) {
        SpringApplication.run(RediscacheApplication.class, args);
    }

}
複製代碼

6、Demo效果測試

準備工做

測試以前,先經過Postman提交數據,向數據庫插入兩條記錄:

插入
清空redis的緩存

127.0.0.1:6379> flushall
OK
複製代碼

一、Cacheable

分別訪問兩次

localhost/testCacheable/1
localhost/testCacheable/2
複製代碼

控制檯打印狀況:

控制檯
由上圖可得,兩條語句均只打印一次,再查詢redis:

127.0.0.1:6379> keys *
1) "User::2"
2) "User::1"
127.0.0.1:6379> 
複製代碼

可發現,已經使用做爲二級緩存。

二、CachePut

清空緩存後分別訪問兩次

localhost/testCachePut/1
localhost/testCachePut/2
複製代碼

再訪問

localhost/testCacheable/1
複製代碼

控制檯打印:

控制檯打印
上圖共有四條SQL語句執行,可發現每次訪問 @CachePut註解標註的方法時都會直接從數據庫查詢,而且查詢結果已經存入緩存。

三、CacheEvict

一、不開啓allEntries

測試前先訪問兩次@Cacheable標註的路徑完成緩存,而後分別訪問

http://localhost/testCacheEvict/1
http://localhost/testCacheable/1
http://localhost/testCacheable/2
複製代碼

控制檯打印:

控制檯輸出
可發現,用戶張三的緩存已被清除,李四不受影響,再次訪問testCacheable/1會從數據庫查詢並從新緩存張三。

二、開啓allEntries

測試前先訪問兩邊@Cacheable標註的路徑完成緩存,而後分別訪問

http://localhost/testAllEntries
http://localhost/testCacheable/1
http://localhost/testCacheable/2
複製代碼

控制檯打印:

控制檯輸出
可發現,用戶張3、李四的緩存均被清空,再次查詢會調用數據庫從新緩存。

6、CacheManager的定製

一、未定製前

當咱們使用引入redis的starter時,容器中默認使用的是RedisCacheManager。它在操做redis時默認採用JDK的序列化機制,例如redis中查看張三的緩存:

JDK配置
咱們能夠經過定製 RedisCacheManager改變採起的序列化機制。

二、進行定製

配置類

@Configuration
public class Config {

    @Bean
    public RedisCacheManager JsonCacheManager(RedisConnectionFactory factory) {
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                // 使用GenericJackson2JsonRedisSerializer序列化獲得Value
                .serializeValuesWith(RedisSerializationContext.SerializationPair.
                        fromSerializer(new GenericJackson2JsonRedisSerializer()));
        return RedisCacheManager.builder(factory)
                .cacheDefaults(config)
                .build();
    }
}


複製代碼

緩存以後查看:

Json
到此,已經完成Json的序列化。其餘配置可根據 RedisCacheConfiguration中的不一樣方法配置。
相關文章
相關標籤/搜索