这里新增加一个例子:
`
package com.atguigu.cache.service;
import com.atguigu.cache.bean.Employee;
import com.atguigu.cache.mapper.EmployeeMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.*;
import org.springframework.stereotype.Service;
@CacheConfig(cacheNames = "emp")
[@Service](https://my.oschina.net/service)
public class EmployeeService {
@Autowired
EmployeeMapper employeeMapper;
/**
* 将方法的运行结果进行缓存,以后在要相同的数据,直接从缓存中获取,不用调用方法
*
* CacheManager管理多个Cache组件的,对缓存的真正CRUD操作在Cache组件中,每一个缓存
* 组件有自己唯一一个名字
*
* 几个属性:
* cacheName/value:指定缓存组件的名字;将方法的返回结果放在哪个缓存中,是数组的方式,可以指定多个缓存;
* key:缓存数据使用的key,可以用它来指定,默认是使用方法参数的值 1-方法的返回值
* 编写SqEL; #id,参数id的值 #a0 #p0 #root.args[0]
* keyGenerator:key的生成器;可以自己指定key的生成器的组件
* key/keyGenerator:二选一使用
* cacheManager:缓存管理器;或者cacheResolver指定获取解析器
* condition:指定符合条件的情况下才缓存;
* condition="#id>0"
* condition="#a0>1"l;第一个参数的值>1 的时候才进行缓存
* (a0等于arg[0])
* unless:否定缓存;当unless指定的条件为true,方法的返回值就不会被缓存;可以
* 获取到结果进行判断unless="#a0==2":如果第一参数的值是2,结果不缓存
* sync:是否使用异步模式:异步模式不支持unless
*
* 原理:
* 1.缓存的自动配置类;CacheAutoConfiguration
* 2.缓存的配置类
* org.springframework.boot.autoconfigure.cache.GenericCacheConfiguration
* org.springframework.boot.autoconfigure.cache.JCacheCacheConfiguration
* org.springframework.boot.autoconfigure.cache.EhCacheCacheConfiguration
* org.springframework.boot.autoconfigure.cache.HazelcastCacheConfiguration
* org.springframework.boot.autoconfigure.cache.InfinispanCacheConfiguration
* org.springframework.boot.autoconfigure.cache.CouchbaseCacheConfiguration
* org.springframework.boot.autoconfigure.cache.RedisCacheConfiguration
* org.springframework.boot.autoconfigure.cache.CaffeineCacheConfiguration
* org.springframework.boot.autoconfigure.cache.SimpleCacheConfiguration【默认】
* org.springframework.boot.autoconfigure.cache.NoOpCacheConfiguration
* 3.哪个配置类生效; SimpleCacheConfiguration
*
* 4.给容器中注册了一个CacheManager、ConcurrentMapCacheManager
* 5.可以获取和创建ConcurrentMapCache类型的缓存组件;他的作用将数据保存在ConcurrentMap中;
*
* 运行流程:
* @Cacheable:
* 1.方法运行之前,先去查询Cache(缓存组件),按照cacheNames指定的名字获取;
* (CacheManager先获取相应的缓存),第一次获取缓存如果没有Cache组件会自动创建,
* 2.去Cache中查找缓存的内容,使用一个key,默认就是方法的参数;
* key是按照某种策略生成的;默认是使用keyGenerator生成的,默认使用
* SimpleKeyGenerator生成key的默认策略;
* 如果没有参数;key=new SimpleKey();
* 如果有一个参数,key=参数的值
* 如果有多个参数:key=new SimpleKey(params);
* 3.没有查到缓存就调用目标方法;
* 4.将目标方法的缓存结果,放进缓存中
*
* @Cacheable标注的方法执行之前先来检查缓存中有没有这个数据,默认按照参数的值作为key去查询缓存,
* 如果没有就运行方法并将结果放入缓存,以后再来调用就可以直接使用缓存中的数据
*
* 核心:
* 1)、使用CacheManager【ConcurrentMapCacheManager】按照名字得到Cache【ConcurrentMapCache】组件
* 2)、key使用keyGenerator生成的,默认是SimpleKeyGenerator
* @param id
* @return
*/
@Cacheable(value = {"emp"}/*,keyGenerator = "myKeyGenerator",condition = "#a0>1",unless = "#a0==2"*/)
public Employee getEmp(Integer id){
System.out.println("查询"+id+"号员工");
Employee emp=employeeMapper.getEmpById(id);
return emp;
}
/**
* @CachePut:即调用方法,又更新缓存数据:同步更新缓存 注意key要相同
* 修改了数据库的某个数据,同时更新缓存;
* 运行时机:
* 1、先调用目标方法
* 2、将目标方法的结果缓存起来
*
* 测试步骤:
* 1、查询1号员工;查到的结果会放在缓存中
* key:1 value: lastName:张三
* 2、以后查询还是之前的结果
* 3、更新1号员工;【LastName:zhangsan:gender:0】
* 将方法的返回值也放进缓存了;
* key: 传入的employee对象 值:返回employee对象;
* 4、查询1号员工?
* 应该是更新后的员工;
* key = "#employee.id":使用传入的参数的员工的id;
* key = "#result.id";使用返回后的id
* @Cacheable的key是不能用#result:
* 原因:因为@Cacheable运行时机有两个,一个是在运行方法之前
* 一个是在运行方法之后,我们要在方法一开始就得到key,Put
* 是先执行方法的,而able是先执行注解的
* 为什么是没更新前的?【1号员工更新了,只是用的key不一样】
*/
@CachePut(/*value = "emp",*/key = "#result.id")
public Employee updateEmp(Employee employee){
System.out.println("updateEmp:"+employee);
employeeMapper.updateEmp(employee);
return employee;
}
/**
* @CacheEvict:缓存清除
* key:指定要清除的数据
* allEntries=true:指定清除这个缓存中所有数据
* beforeInvocation=false:缓存的清除是否在方法之前执行
* 默认代表缓存清除操作是在方法执行之后执行;如果出现异常缓存就
* 不会清除
*
* beforeInvocation = true:
* 代表清除缓存操作是在方法运行之前执行,无论是否出现异常,缓存都清除
*/
@CacheEvict(/*value = "emp",*/beforeInvocation = true/*,key = "#id"*/)
public void deleteEmp(Integer id){
System.out.println("deleteEmp:"+id);
/*employeeMapper.deleteEmpById(id);*/
}
/**
* @Caching 定义复杂的缓存规则
* 这里意味着当你再用id或email调用时,则不需要再执行SQL语句
* @param lastName
* @return
*/
@Caching(
cacheable = {
@Cacheable(/*value = "emp",*/key = "#lastName")
},
put = {
@CachePut(/*value = "emp",*/key = "#result.id"),
@CachePut(/*value = "emp",*/key = "#result.email")//有@CachePut出现,下面的方法就一定会执行
}
) //你依照id,邮箱,名字都可以获得该value
public Employee getEmpByLastName(String lastName){
System.out.println("复杂缓存");
return employeeMapper.getEmpByLastName(lastName);
}
}
` 这里主要说了SpringCache注解的功能,并且更加详细
但是我在另一项目中使用这些注解却出现了一些意外主要是因为key原本是String类型,但是我没有将负值key为id的属性转成String,这里则说明有些需要转型,有些则不需要:
`
package cn.enilu.subor.service.system.impl;
import cn.enilu.subor.bean.entity.system.Video;
import cn.enilu.subor.dao.system.VideoRepository;
import cn.enilu.subor.service.system.VideoService;
import cn.enilu.subor.utils.factory.MutiStrFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import java.util.List;
@CacheConfig(cacheNames = "video")
@Service
public class VideoServiceImpl implements VideoService {
@Autowired
private VideoRepository videoRepository;
@Override
public Page<Video> findAll(Pageable var1) {
return videoRepository.findAll(var1);
}
@Override
//@Cacheable(value = {"video"})
public List<Video> findAll() {
return videoRepository.findAll();
}
@Override
@CachePut(key = "#video.id.toString()")
public Video save(Video video) {
return videoRepository.save(video);
}
@Override
@CacheEvict(key = "#id.toString()")
public void delete(Integer id) {
System.out.println("dddddddddddddddddddd"+id);
videoRepository.delete(id);
}
@CachePut(key = "#video.id.toString()")
public void update(Video video){
System.out.println("uuuuuuu");
System.out.println("38218401779274902148901249012"+video);
Integer videoId=video.getId();
//String title=video.getTitle();
String video_introduce=video.getVideoIntroduce();
String video_type=video.getVideoType();
Integer video_class=video.getVideoClass();
//String video_url=video.getVideoUrl();
//String img_title=video.getImgTitle();
// String img_url=video.getImgUrl();
videoRepository.updateById2(video_class,video_introduce,video_type,videoId);
}
}
`
这里在附上注解的源码,key的类型为String
`
package org.springframework.cache.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface CachePut {
@AliasFor("cacheNames")
String[] value() default {};
@AliasFor("value")
String[] cacheNames() default {};
String key() default "";
String keyGenerator() default "";
String cacheManager() default "";
String cacheResolver() default "";
String condition() default "";
String unless() default "";
}
`