SpringBoot+SpringCache+Redis补充

本文详细介绍了 Spring Cache 注解的功能及使用方法,包括 @Cacheable、@CachePut 和 @CacheEvict 的工作原理和应用场景,并通过具体代码示例展示了如何在实际项目中应用这些注解。

这里新增加一个例子:

`

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

`

转载于:https://my.oschina.net/u/3843989/blog/1831469

<think>好的,我需要帮助用户了解如何启动一个Spring Boot与Vue集成的项目。用户提供的引用内容中有三个相关的参考资料,我需要结合这些内容来构建一个清晰的步骤指南。 首先,我得整理启动过程的主要步骤。通常,这样的项目分为后端(Spring Boot)和前端(Vue)两部分,可能需要分别启动。根据引用[2],项目后端使用Java、MySQL、Redis,前端用Vue,所以需要确保这些环境已经安装配置好。 接下来,用户提到的引用[3]中提到JDK版本的问题,需要注意将JDK设置为1.8,避免IDE使用旧版本。这点很重要,需要特别提醒用户检查JDK配置。 然后,前端部分需要Node.js环境,安装依赖并启动。引用[3]还提到了npm run dev报错的问题,可能需要检查依赖安装是否正确或配置文件是否有误。 另外,引用[1]是关于Vue Devtools的安装,虽然对项目启动不是必须,但可能对开发有帮助,可以作为补充建议。 现在需要将这些步骤分点说明,结构要清晰。可能需要分为环境准备、后端启动、前端启动、常见问题几个部分。每个步骤详细说明,同时引用相关的参考资料来支持。 还要注意用户可能遇到的常见问题,如JDK版本、依赖安装错误、端口冲突等,根据引用内容中的问题点进行解答。 最后,生成相关问题,比如环境配置问题、启动错误处理、前后端交互等,方便用户进一步了解。 需要确保使用正确的中文表达,避免技术术语错误,同时按照用户的格式要求使用$...$和$$...$$格式,不过在这个回答中可能数学公式较少,但如果有代码块或命令,需要用正确的格式呈现。 现在开始组织内容,确保每个步骤都有对应的引用支持,并自然地将引用标识放在相关段落末尾。</think>### Spring Boot与Vue集成项目启动教程 #### 一、环境准备 1. **JDK 1.8+** 确保安装JDK 1.8或更高版本,并在IDE(如IntelliJ IDEA)中配置正确的JDK路径。若IDE默认使用旧版本(如1.5),需手动修改配置[^3]。 **验证命令**: ```bash java -version ``` 2. **Node.js与npm** Vue前端需要Node.js环境(建议安装LTS版本),并确保npm包管理器可用。 **验证命令**: ```bash node -v npm -v ``` 3. **数据库与缓存** 根据项目需求安装MySQL和Redis,并配置连接信息(通常位于后端`application.properties`文件中)。 --- #### 二、后端启动(Spring Boot) 1. **导入项目** 使用IDE(如IntelliJ IDEA)导入Maven项目,等待依赖自动下载。 2. **配置数据库** 修改`src/main/resources/application.properties`中的数据库连接信息,例如: ```properties spring.datasource.url=jdbc:mysql://localhost:3306/your_db spring.datasource.username=root spring.datasource.password=123456 ``` 3. **启动Spring Boot应用** 找到主启动类(含`@SpringBootApplication`注解),直接运行。 **成功标志**:控制台输出`Started Application in X seconds`。 --- #### 三、前端启动(Vue) 1. **安装依赖** 进入前端项目根目录,执行: ```bash npm install ``` 若报错,可尝试清除缓存后重装: ```bash npm cache clean --force npm install ``` 2. **配置代理(可选)** 修改`vue.config.js`中的代理设置,确保API请求指向后端地址: ```javascript devServer: { proxy: 'http://localhost:8080' // Spring Boot默认端口 } ``` 3. **启动开发服务器** ```bash npm run dev ``` **成功标志**:浏览器自动打开`http://localhost:8081`(端口可能不同)。 --- #### 四、常见问题 1. **JDK版本不匹配** IDEA若提示JDK版本过低,需在`File > Project Structure > Project`中手动选择JDK 1.8[^3]。 2. **npm依赖安装失败** - 检查网络是否允许访问npm仓库。 - 尝试使用`cnpm`(淘宝镜像)替代npm。 3. **端口冲突** 若后端端口被占用,可在`application.properties`中修改: ```properties server.port=9090 ``` 4. **跨域问题** 确保前端代理配置正确,或后端添加CORS配置。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值