三、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分鐘!