SpringBoot+SpringCache+Redis补充

这里新增长一个例子:java

`spring

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号员工;查到的结果会放在缓存中
	 *          key:1  value: lastName:张三
	 *   二、之后查询仍是以前的结果
	 *   三、更新1号员工;【LastName:zhangsan:gender:0】
	 *          将方法的返回值也放进缓存了;
	 *          key: 传入的employee对象 值:返回employee对象;
	 *   四、查询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);
	}

}

`app

这里在附上注解的源码,key的类型为Stringless

`dom

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 "";
}

`异步