1. 程式人生 > >三、springboot-redis快取使用

三、springboot-redis快取使用

一、建立springboot專案

二、pom.xml新增以下依賴

            <dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-redis</artifactId>
		</dependency>

		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>1.3.1</version>
		</dependency>

		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.46</version>
		</dependency>

		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid</artifactId>
			<version>1.1.9</version>
		</dependency>

		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<version>1.16.22</version>
		</dependency>

三、使用

1、啟動類添加註解@EnableCaching

2、application.properties配置redis的host、post、password

#redis
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=tiger

3、application.properties配置mysql

#datasource
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/tiger?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&autoReconnect=true&generateSimpleParameterMetadata=true
spring.datasource.username=tiger
spring.datasource.password=tiger
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.max-idle=10
spring.datasource.max-wait=60000
spring.datasource.min-idle=5
spring.datasource.initial-size=5
spring.datasource.validationQuery=select 'x'

4、建立學生資訊表

CREATE TABLE student_info (
  id bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增',
  student_id bigint(20) NOT NULL COMMENT '學號',
  name varchar(64) NOT NULL COMMENT '姓名',
  age int(2) NOT NULL COMMENT '年齡',
  familly_address varchar(256) NOT NULL COMMENT '家庭地址',
  created_date datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '建立時間',
  updated_date datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新時間',
  PRIMARY KEY (student_id),
  KEY id (id)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4

5、建立實體類:StudentInfo

package com.dl.cn.message.bean;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.util.Date;

/**
 * Created by Tiger on 2018/10/8.
 */
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class StudentInfo implements Serializable{

    private static final long serialVersionUID = 2597547944454691103L;

    private Long id;
    private Long studentId;
    private String name;
    private Integer age;
    private String famillyAddress;
    private Date createdDate;
    private Date updatedDate;
}

6、mapper類:StudentInfoMapper

package com.dl.cn.message.mapper;

import com.dl.cn.message.bean.StudentInfo;
import org.apache.ibatis.annotations.*;

/**
 * Created by Tiger on 2018/10/8.
 */
@Mapper
public interface StudentInfoMapper {
    @Insert("insert into student_info(student_id,name,age,familly_address)" +
            " values(#{studentId},#{name},#{age},#{famillyAddress})")
    /**
     * 通過bean儲存實體類是,建議不要通過@Param註解,負責實體類的屬性都在@Param中找
     * */
    void saveStudentInfo(StudentInfo studentInfo);


    @Select("select * from student_info where student_id = #{studentId}")
    StudentInfo findByStudentId(@Param("studentId") Long studentId);


    @Update("update student_info set familly_address = #{famillyAddress},updated_date = now() ")
    void updateFamillyAddress(@Param("studentId") Long studentId,@Param("famillyAddress") String famillyAddress);
}

7、service類:StudentInfoService

package com.dl.cn.message.service;

import com.dl.cn.message.bean.StudentInfo;
import com.dl.cn.message.mapper.StudentInfoMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * Created by Tiger on 2018/10/8.
 */
@Service
public class StudentInfoService {

    @Autowired
    StudentInfoMapper studentInfoMapper;

    /**
     * 儲存學生資訊
     * @param studentInfo
     * */
    public void saveStudentInfo(StudentInfo studentInfo){
        studentInfoMapper.saveStudentInfo(studentInfo);
    }

    /**
     * 根據學號查學生資訊
     * @param studentId
     * @return
     * */
    public StudentInfo findByStudentId(Long studentId){
        return studentInfoMapper.findByStudentId(studentId);
    }

    /**
     * 根據學號更新家庭地址
     * @param studentId
     * @param famillyAddress
     * */
    public void updateFamillyAddress(Long studentId,String famillyAddress){
        studentInfoMapper.updateFamillyAddress(studentId,famillyAddress);
    }
}

8、controller類:StudentInofController

package com.dl.cn.message.controller;

import com.dl.cn.message.service.StudentInfoService;
import com.dl.cn.message.bean.StudentInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * Created by Tiger on 2018/10/8.
 */
@RestController
@RequestMapping("/student")
@CacheConfig(cacheNames = "studentInfo")
@Slf4j
public class StudentInofController {
    @Autowired
    StudentInfoService studentInfoService;

    /**
     * 儲存學生資訊
     * @param studentId
     * @param name
     * @param age
     * @param famillyAddress
     * */
    @PostMapping("/save")
    public void saveStudentInfo(@RequestParam("student_id") Long studentId,
                                @RequestParam("name") String name,
                                @RequestParam("age") Integer age,
                                @RequestParam("familly_address") String famillyAddress){
        StudentInfo studentInfo = StudentInfo.builder()
                .studentId(studentId)
                .name(name)
                .age(age)
                .famillyAddress(famillyAddress)
                .build();
        studentInfoService.saveStudentInfo(studentInfo);
    }

    /**
     * 根據學號查學生資訊
     * @param studentId
     * @return
     * */
    @PostMapping("/findByStudentId")
    @Cacheable(key = "#studentId")
    public StudentInfo findByStudentId(@RequestParam("student_id") Long studentId){
        log.info("Get student information based on student number:{}",studentId);
        System.out.println("查詢資訊>>>"+studentId);
        return studentInfoService.findByStudentId(studentId);
    }

    @PostMapping("/updateFamillyAddress")
    //刪除對應key的快取
    @CacheEvict(key = "#studentId")
    public void updateFamillyAddress(@RequestParam("student_id") Long studentId,
                                     @RequestParam("familly_address") String famillyAddress){
        studentInfoService.updateFamillyAddress(studentId,famillyAddress);
    }

}

四、說明

1、快取的實體類必須序列號,IDEA可以安裝serialVersionUID外掛,然後自己定義快捷鍵

2、@Cacheable註解,快取到redis

cacheNames:指定快取的名稱

key:定義組成的key值,如果不定義,則使用全部的引數計算一個key值。可以使用spring El表示式

condition:在執行方法之前條件判斷,滿足條件快取,負責不快取

unless:在執行方法之後條件判斷,不滿足條件返回true,滿足條件返回false

key 的值可以指定沒固定值,也可以取方法引數,例如:key = "#studentId"

sync:redis中有值時,多個執行緒可以同時訪問,如果沒有值,只允許一個執行緒查詢

3、@CacheEvict註解,刪除指定的key

cacheNames:指定快取的名稱

key:定義組成的key值,如果不定義,則使用全部的引數計算一個key值。可以使用spring El表示式

4、@cachePut註解,更新資料之後,更新redis對應key的值,和@Cacheable配套使用,但是新增這兩個註解的方法,返回必須一樣

5、@CacheConfig註解,作用域是當前類,這樣不需要每個類設定cacheName的值

五、測試結果

1、在方法findByStudentId新增@Cacheable註解,預期結果是第一次查詢從mysql獲取資訊,此後從redis獲取資訊

第一次進入了方法體:

第二次、第三次之後沒有進入方法體,說明快取成功了,檢視redis,找到對應的key

2、在方法updateFamillyAddress上添加了註解@CacheEvict,預期結果是根據學號修改學生家庭住址,在redis刪除對應key的值,然後重新從mysql獲取資訊

將13240115對應的學生家庭地址修改為北京,redis對應的key被刪除

再次獲取13240115學生的資訊,從mysql獲取資訊

六、問題

1、從mysql查詢的欄位,student_id,created_date,update_date,familly_address值為null,因為在application.properties沒有開啟mybatis駝峰命名,

#mybatis
#開啟mybatis駝峰命名,這樣可以將mysql中帶有下劃線的對映成駝峰命名的欄位
mybatis.configuration.map-underscore-to-camel-case=true

2、redis快取的key沒有過期時間,如何給對應快取設定過期時間

springboot2.0以後的配置方法

 @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        //生成一個預設配置,通過config物件即可對快取進行自定義配置
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
        // 設定快取的預設過期時間,也是使用Duration設定
        config = config.entryTtl(Duration.ofSeconds(60*2))
                .disableCachingNullValues();// 不快取空值
        //設定一個初始化的快取空間set集合
        Set<String> cacheNames =  new HashSet<>();
        cacheNames.add("studentInfo");

        // 對每個快取空間應用不同的配置
        Map<String, RedisCacheConfiguration> configMap = new HashMap<>();
        configMap.put("studentInfo", config);

        RedisCacheManager cacheManager = RedisCacheManager.builder(factory)     // 使用自定義的快取配置初始化一個cacheManager
                .initialCacheNames(cacheNames)  // 注意這兩句的呼叫順序,一定要先呼叫該方法設定初始化的快取名,再初始化相關的配置
                .withInitialCacheConfigurations(configMap)
                .build();
        return cacheManager;
    }
cacheNames中可以設定程式碼中多個快取名,然後分別給設定過期時間,這裡設定了2分鐘!