一、环境准备:
1、redis相关关键记录:
1)启动:进入到redis安装目录的src下,启动命令是:./redis-server ../redis.conf。
2)连接:在redis.conf文件内需要设置绑定地址:bind 192.168.60.129,否则远程无法访问redis。
2、项目基础是 SpringBoot2.X之旅,Mybatis+Durid+Mysql实践,mybatis自定义sql语句和多表关联查询(Web Project)这篇文章的基础上进行改造的。
3、本文是在一个基本的spring boot + mybatis的web项目中,实现CURD和简单的集合查询,把查询结果进行缓存。
用redis实现结果缓存的关键步骤:
a、添加redis的依赖
b、涉及到缓存的数据类需要实现序列化
c、添加redis数据库的地址、端口配置
d、在需要缓存返回结果的方法上加@Cacheable,设定参数
e、启动类上加@EnableCaching注解,开启缓存
f、@CacheEvict删除缓存
g、@CachePut,当数据有修改的返回值与查询相同使用,先删除缓存,再把返回值存到缓存
h、@CacheConfig同一个类里抽取出cacheNames 参数
二、项目改造:
1、添加依赖:
<!--redis依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
最终项目的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.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.cobra</groupId>
<artifactId>mybatisdemo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>mybatisdemo</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-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--加入druid依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<!--redis依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!--添加mybatis generator生成器插件-->
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.7</version>
<!--生成插件的依赖-->
<dependencies>
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.7</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
</dependencies>
<!--所要做的事情-->
<executions>
<execution>
<!--起个名-->
<id>mybatis generator</id>
<!--阶段-->
<phase>package</phase>
<!--目的-->
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<!--由于需要反复生成文件,这里是一些相关配置-->
<configuration>
<!--允许移动生成文件-->
<verbose>true</verbose>
<!--允许覆盖文件,实际开发中这个不能为true,
不然可能把别人的劳动成果覆盖-->
<overwrite>true</overwrite>
<!--mybatis-generator配置文件的路径-->
<configurationFile>
src/main/resources/mybatis-generator.xml
</configurationFile>
</configuration>
</plugin>
</plugins>
</build>
</project>
2、dao层,UserInfoMapper.xml添加查询
<!--查询所有人-->
<select id="listUser" resultMap="BaseResultMap">
<!--
WARNING - @mbg.generated
This element is automatically generated by MyBatis Generator, do not modify.
This element was generated on Sat Mar 16 10:50:50 CST 2019.
-->
select
<include refid="Base_Column_List" />
from user_info order by user_id asc;
</select>
UserInfoMapper接口添加查询方法
/**
* 获取所有人
* @return
*/
List<UserInfo> listUser();
3、service层:
UseService添加接口:
/**
* 查找所有UserInfo
* @return
*/
public List<UserInfo> findAll();
UseServiceImpl实现接口:
/**
* 查找所有UserInfo
*
* @return
*/
@Override
public List<UserInfo> findAll() {
return userInfoMapper.listUser();
}
三、用@Cacheable对查询结果进行缓存(需要做的额外关键点):
1、需要返回的数据实体需要序列化,实现Serializable,生成私有id:
package com.cobra.mybatisdemo.dataobject;
import java.io.Serializable;
/**
* UserInfo数据实体
*/
public class UserInfo implements Serializable {
private static final long serialVersionUID = -7942802606015631488L;
/**
*
* This field was generated by MyBatis Generator.
* This field corresponds to the database column user_info.user_id
*
* @mbg.generated Sat Mar 16 10:50:50 CST 2019
*/
private Integer userId;
/**
*
* This field was generated by MyBatis Generator.
* This field corresponds to the database column user_info.username
*
* @mbg.generated Sat Mar 16 10:50:50 CST 2019
*/
private String username;
/**
*
* This field was generated by MyBatis Generator.
* This field corresponds to the database column user_info.password
*
* @mbg.generated Sat Mar 16 10:50:50 CST 2019
*/
private String password;
/**
*
* This field was generated by MyBatis Generator.
* This field corresponds to the database column user_info.email
*
* @mbg.generated Sat Mar 16 10:50:50 CST 2019
*/
private String email;
/**
* This method was generated by MyBatis Generator.
* This method returns the value of the database column user_info.user_id
*
* @return the value of user_info.user_id
*
* @mbg.generated Sat Mar 16 10:50:50 CST 2019
*/
public Integer getUserId() {
return userId;
}
/**
* This method was generated by MyBatis Generator.
* This method sets the value of the database column user_info.user_id
*
* @param userId the value for user_info.user_id
*
* @mbg.generated Sat Mar 16 10:50:50 CST 2019
*/
public void setUserId(Integer userId) {
this.userId = userId;
}
/**
* This method was generated by MyBatis Generator.
* This method returns the value of the database column user_info.username
*
* @return the value of user_info.username
*
* @mbg.generated Sat Mar 16 10:50:50 CST 2019
*/
public String getUsername() {
return username;
}
/**
* This method was generated by MyBatis Generator.
* This method sets the value of the database column user_info.username
*
* @param username the value for user_info.username
*
* @mbg.generated Sat Mar 16 10:50:50 CST 2019
*/
public void setUsername(String username) {
this.username = username == null ? null : username.trim();
}
/**
* This method was generated by MyBatis Generator.
* This method returns the value of the database column user_info.password
*
* @return the value of user_info.password
*
* @mbg.generated Sat Mar 16 10:50:50 CST 2019
*/
public String getPassword() {
return password;
}
/**
* This method was generated by MyBatis Generator.
* This method sets the value of the database column user_info.password
*
* @param password the value for user_info.password
*
* @mbg.generated Sat Mar 16 10:50:50 CST 2019
*/
public void setPassword(String password) {
this.password = password == null ? null : password.trim();
}
/**
* This method was generated by MyBatis Generator.
* This method returns the value of the database column user_info.email
*
* @return the value of user_info.email
*
* @mbg.generated Sat Mar 16 10:50:50 CST 2019
*/
public String getEmail() {
return email;
}
/**
* This method was generated by MyBatis Generator.
* This method sets the value of the database column user_info.email
*
* @param email the value for user_info.email
*
* @mbg.generated Sat Mar 16 10:50:50 CST 2019
*/
public void setEmail(String email) {
this.email = email == null ? null : email.trim();
}
@Override
public String toString() {
return "UserInfo{" +
"userId=" + userId +
", username='" + username + '\'' +
", password='" + password + '\'' +
", email='" + email + '\'' +
'}';
}
}
2、application.yml配置文件添加redis地址和端口,如果有密码需要填写密码:
spring:
redis:
host: 192.168.60.129
port: 6379
3、controller层:
UserController添加映射mapping方法,加上缓存注解@Cacheable并指定参数(cacheNames = "user",key = "123456"):
/**
* 获取所有的UserInfo
* @return
*/
@GetMapping("/list")
@Cacheable(cacheNames = "user",key = "123456")
public List<UserInfo> findAll() {
return userService.findAll();
}
4、启动类上加@EnableCaching注解,开启缓存:
package com.cobra.mybatisdemo;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
@SpringBootApplication
@MapperScan("com.cobra.mybatisdemo.dao")
@EnableCaching
public class MybatisdemoApplication {
public static void main(String[] args) {
SpringApplication.run(MybatisdemoApplication.class, args);
}
}
四、测试:
1、打断点:
2、用debug模式启动项目:
3、首次访问:localhost:8080/user/list
4、进入断点:
5、返回结果:
6、同时使用redis管理工具查看redis,发现有存入值:
7、第二次及之后的访问,可以发现,请求不会到断点,说明数据是直接去redis读的缓存。
五、@CacheEvict删除缓存数据
当修改、添加、删除数据时,为了保证缓存数据和数据库的数据一致,需要需要删除缓存,让客户端在修改、添加、删除数据之后,首次访问数据库,再生成缓存,但是要保证cacheNames、key 和@Cacheable一致:
package com.cobra.mybatisdemo.controller;
import com.cobra.mybatisdemo.dataobject.UserInfo;
import com.cobra.mybatisdemo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @Author: Baron
* @Description:
* @Date: Created in 2019/3/16 12:10
*/
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
UserService userService;
/**
* 添加用户
* @param userInfo
* @return
*/
@PostMapping("/add")
@CacheEvict(cacheNames = "user",key = "123456")
public int add(UserInfo userInfo) {
return userService.add(userInfo);
}
/**
* 根据userId查找用户
* @param userId
* @return
*/
@GetMapping("/{userId}")
public UserInfo findByUserId(@PathVariable("userId") Integer userId) {
return userService.findByUserId(userId);
}
/**
* 更改用户信息
* @param userInfo
* @return
*/
@PostMapping("/update")
@CacheEvict(cacheNames = "user",key = "123456")
public int update(UserInfo userInfo) {
return userService.update(userInfo);
}
/**
* 根据userId删除用户
* @param userId
* @return
*/
@DeleteMapping("/{userId}")
@CacheEvict(cacheNames = "user",key = "123456")
public int deleteByUserId(@PathVariable("userId") Integer userId) {
return userService.deleteByUserId(userId);
}
/**
* 获取所有的UserInfo
* @return
*/
@GetMapping("/list")
@Cacheable(cacheNames = "user",key = "123456")
public List<UserInfo> findAll() {
return userService.findAll();
}
}
六、@CachePut先删原来的缓存,再把返回的缓存放入redis
适用于数据修改之后有返回值的缓存,返回类型需要与查询的一样,一般与@Cacheable结合使用,cacheNames 、key参数需要一致。
七、@CacheConfig抽取cacheNames 参数
如果在同一个类上,有多个方法使用@Cacheable、@CachePut、@CacheEvict,可以使用@CacheConfig(cacheNames = "user")把公共部分提取出来。
项目demo地址:https://github.com/yaobaron/redisdemo/