最近想用redis在项目中用缓存,就是在按照网上的教程配置了下,然而卵用没有,许多内容看不懂,还有许多误导性的东西,无奈,从源头开始看,梳理一些基础知识,需要注意,在用各种缓存之前,一定要将这些东西看完。
话不多说,为什么用缓存这些就不说了,先来了解下 JSR107规范,这是基础。
Java Specification Requests 简称 JSR,是java提供的一个接口规范,类似于JDBC规范,没有具体的实现,具体的实现就是reids等这些缓存。
Java Caching定义了5个核心接口,分别是CachingProvider, CacheManager, Cache, Entry和Expiry。
javax.cache
cache-api
Spring从3.1开始定义了org.springframework.cache.Cache和org.springframework.cache.CacheManager接口来统一不同的缓存技术;并支持使用JCache(JSR-107)注解简化我们开发;
1 Cache接口为缓存的组件规范定义,包含缓存的各种操作集合;
2 Cache接口下Spring提供了各种xxxCache的实现,如RedisCache,EhCacheCache , ConcurrentMapCache等;每次调用需要缓存功能的方法时,Spring会检查检查指定参数的指定的目标方法是否已经被调用过;如果有就直接从缓存中获取方法调用后的结果,如果没有就调用方法并缓存结果返回给用户。下次直接从缓存中获取。
• Generic
• JCache (JSR-107)
• EhCache 2.x
• Hazelcast
• Infinispan
• Redis
• Guava
• Simple
除了按顺序侦测外,我们也可以通过配置属性spring.cache.type来强制指定。
org.springframework.boot
spring-boot-starter-cache
@SpringBootApplication
@MapperScan("com.example.dao")
@EnableSwagger2
@EnableCaching // 启动类开启缓存支持
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
package com.example.model;
import java.io.Serializable;
public class UserModel implements Serializable {
private Integer id;
private String userName;
private String email;
private Integer gender; // 1 男 0 女
public UserModel() {
}
public UserModel(Integer id, String userName, String email, Integer gender) {
this.id = id;
this.userName = userName;
this.email = email;
this.gender = gender;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Integer getGender() {
return gender;
}
public void setGender(Integer gender) {
this.gender = gender;
}
@Override
public String toString(){
return "UserModel = [id="+this.id+",username="+this.userName+",email="+this.email+",gender="+this.gender+"]";
}
}
package com.example.dao;
import com.example.model.UserModel;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
public interface UserMapper {
@Select("select * from user_info where id=#{id}")
UserModel getUserById(Integer id);
@Select("select * from user_info where userName=#{userName}")
UserModel getUserByName(String userName);
@Insert("insert into user_info values (id_seq.nextval,#{userName},#{email},#{gender})")
void insertUser(UserModel userModel);
@Update("update user_info set userName=#{userName},email=#{email},gender=#{gender} where id=#{id}")
void updateUserById(UserModel userModel);
@Delete("delete from user_info where id=#{id}")
void deleteUserById(Integer id);
@Select("select id_seq.currval from dual")
int getCurrentIdSeq();
}
package com.example.dto;
import io.swagger.annotations.ApiModelProperty;
public class UserDto {
@ApiModelProperty(value = "用户名",required = true)
private String userName;
@ApiModelProperty(value = "电子邮件",required = true)
private String email;
@ApiModelProperty(value = "性别",required = true)
private Integer gender;
@ApiModelProperty(value = "id",required = false)
private Integer id;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Integer getGender() {
return gender;
}
public void setGender(Integer gender) {
this.gender = gender;
}
}
package com.example.service;
import com.example.dao.UserMapper;
import com.example.model.UserModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.stereotype.Service;
@Service
@CacheConfig(cacheNames = "userCache")
public class UserMapperService {
@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
@Autowired
UserMapper userMapper;
@Cacheable(cacheNames = {"userCache"},key = "#id")
public UserModel getUserById(Integer id) {
return userMapper.getUserById(id);
}
@SuppressWarnings("SpringCacheableComponentsInspection")
@Cacheable(cacheNames = {"userCache1"},keyGenerator = "nameKeyGenerator")
public UserModel getUserById2(Integer id) {
return userMapper.getUserById(id);
}
@CachePut(key = "#userModel.id",condition = "#userModel.id != null")
public UserModel insertUser(UserModel userModel) {
userMapper.insertUser(userModel);
int id = userMapper.getCurrentIdSeq();
userModel.setId(id);
return userModel;
}
public void updateUserById(UserModel userModel) {
userMapper.updateUserById(userModel);
}
@CacheEvict(value = "userCache1",key = "#id")
public void deleteUserById(Integer id) {
userMapper.deleteUserById(id);
}
}
package com.example.config;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
@Configuration
public class MyKeyGenerator {
@Bean("nameKeyGenerator")
public KeyGenerator nameKeyGenerator(){
return new KeyGenerator(){
@Override
public Object generate(Object o, Method method, Object... objects) {
System.out.println(o.toString()); //Object o, 调用的类的对象 UserMapperService
System.out.println("method.getName() is "+method.getName()); // 方法。包括整个方法的内容
System.out.println("method.getReturnType() is "+method.getReturnType());
System.out.println("objects is "+objects); // 方法参数
List
有个疑问:当没有缓存时,会调用两次,不知道怎么回事,可能和加载机制有关,没有仔细研究。
package com.example.controller;
import com.example.common.JsonUtil;
import com.example.common.ResponseInfo;
import com.example.common.ResponseUtil;
import com.example.dto.UserDto;
import com.example.model.UserModel;
import com.example.service.UserMapperService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Api(value = "UserController" ,description = "用户控制器,测试缓存")
@RequestMapping("/user")
public class UserController {
private static final Logger log = LoggerFactory.getLogger(StudentController.class);
@Autowired
private UserMapperService userMapperService;
@ApiOperation(value = "Cacheable根据Id查询用户信息,默认的key生产策略",notes = "id:1")
@RequestMapping(value = "/getUserById",method = {RequestMethod.POST})
public ResponseInfo getUserById(Integer id){
log.info("===getUserById request id = "+ id);
ResponseInfo responseInfo = new ResponseInfo<>();
try{
UserModel userModel = userMapperService.getUserById(id);
responseInfo.setRtnCode(ResponseUtil.SUCCESS_CODE);
responseInfo.setRtnMsg(ResponseUtil.SUCCESS_MSG);
responseInfo.setData(userModel);
}catch(Exception e){
e.printStackTrace();
responseInfo.setRtnCode(ResponseUtil.FAIL_CODE);
responseInfo.setRtnMsg(ResponseUtil.FAIL_MSG);
log.info("getUserById 接口异常,错误原因:"+e);
}
return responseInfo;
}
@ApiOperation(value = "Cacheable根据Id查询用户信息,自定义的key生产策略",notes = "userName:张三")
@RequestMapping(value = "/getUserById2",method = {RequestMethod.POST})
public ResponseInfo getUserById2(Integer id){
log.info("=====================>getUserById2 request id = "+ id);
ResponseInfo responseInfo = new ResponseInfo<>();
try{
UserModel userModel = userMapperService.getUserById2(id);
responseInfo.setRtnCode(ResponseUtil.SUCCESS_CODE);
responseInfo.setRtnMsg(ResponseUtil.SUCCESS_MSG);
responseInfo.setData(userModel);
}catch(Exception e){
e.printStackTrace();
responseInfo.setRtnCode(ResponseUtil.FAIL_CODE);
responseInfo.setRtnMsg(ResponseUtil.FAIL_MSG);
log.info("getUserByName 接口异常,错误原因:"+e);
}
return responseInfo;
}
@ApiOperation(value = "根据id删除用户信息",notes = "id:1")
@RequestMapping(value = "/deleteUserById",method = {RequestMethod.POST})
public ResponseInfo deleteUserById(Integer id){
log.info("=================>deleteUserById request id = "+ id);
ResponseInfo responseInfo = new ResponseInfo<>();
try{
userMapperService.deleteUserById(id);
responseInfo.setRtnCode(ResponseUtil.SUCCESS_CODE);
responseInfo.setRtnMsg(ResponseUtil.SUCCESS_MSG);
}catch(Exception e){
e.printStackTrace();
responseInfo.setRtnCode(ResponseUtil.FAIL_CODE);
responseInfo.setRtnMsg(ResponseUtil.FAIL_MSG);
log.info("deleteUserById 接口异常,错误原因:"+e);
}
return responseInfo;
}
@ApiOperation(value = "CachePut 新增用户信息用户信息",notes = "userName:张三")
@RequestMapping(value = "/inserrUser",method = {RequestMethod.POST})
public ResponseInfo inserrUser(@RequestBody UserDto userDto){
log.info("================>inserrUser request params is = "+ JsonUtil.toJsonString(userDto));
ResponseInfo responseInfo = new ResponseInfo<>();
try{
UserModel userModel = new UserModel();
userModel.setUserName(userDto.getUserName());
userModel.setEmail(userDto.getEmail());
userModel.setGender(userDto.getGender());
userMapperService.insertUser(userModel);
responseInfo.setRtnCode("000");
responseInfo.setRtnMsg("添加成功");
}catch(Exception e){
e.printStackTrace();
responseInfo.setRtnCode("200");
responseInfo.setRtnMsg("添加失败");
log.info("inserrUser 接口异常,错误原因:"+e);
}
return responseInfo;
}
@ApiOperation(value = "根据id修改用户信息",notes = "userName:张三")
@RequestMapping(value = "/updateUserById",method = {RequestMethod.POST})
public ResponseInfo updateUserById(@RequestBody UserDto userDto){
log.info("====================>updateUserById request params is = "+ JsonUtil.toJsonString(userDto));
ResponseInfo responseInfo = new ResponseInfo<>();
try{
UserModel userModel = new UserModel();
userModel.setUserName(userDto.getUserName());
userModel.setEmail(userDto.getEmail());
userModel.setGender(userDto.getGender());
userModel.setId(userDto.getId());
userMapperService.updateUserById(userModel);
responseInfo.setRtnCode(ResponseUtil.SUCCESS_CODE);
responseInfo.setRtnMsg(ResponseUtil.SUCCESS_MSG);
responseInfo.setData(userModel);
}catch(Exception e){
e.printStackTrace();
responseInfo.setRtnCode(ResponseUtil.FAIL_CODE);
responseInfo.setRtnMsg(ResponseUtil.FAIL_MSG);
log.info("getUserByName 接口异常,错误原因:"+e);
}
return responseInfo;
}
}