配置文件
<!-- 继承默认值为Spring Boot -->
<parent>
<groupId> org.springframework.boot </groupId>
<artifactId> spring-boot-starter-parent </artifactId>
<version> 2.0.4.RELEASE </version>
</parent>
<dependencies>
<!-- SpringBoot web 核心组件 -->
<dependency>
<groupId> org.springframework.boot </groupId>
<artifactId> spring-boot-starter-web </artifactId>
</dependency>
<!-- SpringBoot对Redis支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- jpa 默认集成了hibernate。 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- aop依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- 热部署 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<!-- 测试包 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<!-- 作为可执行jar的包 -->
<build>
<plugins>
<plugin>
<groupId> org.springframework.boot </groupId>
<artifactId> spring-boot-maven-plugin </artifactId>
</plugin >
</plugins>
</build>
application.yml配置
server:
port: 8080
spring:
jpa:
database: mysql
show-sql: true #显示执行的sql
hibernate:
ddl-auto: update #每次运行更新表
jackson:
serialization:
fail-on-empty-beans: false
datasource:
url: jdbc:mysql://127.0.0.1:3306/springboot-redis?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver
redis:
database: 0
host: #redis安装的服务器地址
port: 6379
password: #redis的密码
jedis:
pool:
max-active: 10 # 连接池最大连接数(使用负值表示没有限制)
max-wait: -1 # 连接池最大阻塞等待时间(使用负值表示没有限制)
max-idle: 8 # 连接池中的最大空闲连接
min-idle: 1 # 连接池中的最小空闲连接
代码实现
1.注解类
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;
/**
* 该注解用于当redis中的信息修改之后,将查询的语句的redis缓存清除
* @author MY
*
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Change {
String key() default "";
}
2.aop类
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import com.my.annotation.Change;
@Component
@Aspect
public class AnnotationAspect {
@Autowired
private RedisTemplate<String,String> redisTemplate;
//要处理的key的后缀
private static List<String> KEY = new ArrayList<String>();
//要处理的key的前缀 如果使用@CacheConfig redis中key 的值会是
private static List<String> CACHE_NAMES = new ArrayList<String>();
private static String JOINT = ":";
//切入点
@Pointcut("execution(public * com.my.service.impl.*.*(..))")
public void aspect() {
}
@Before("aspect()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
//获取当前类
Class<? extends Object> curClass = joinPoint.getTarget().getClass();
//获取CacheConfig注解
CacheConfig annotation = curClass.getAnnotation(CacheConfig.class);
//判断CacheConfig注解是否存在
if(annotation!=null) {
if(annotation.cacheNames()!=null && annotation.cacheNames().length>0) {
CACHE_NAMES = Arrays.asList(annotation.cacheNames());
}
}
//获取类的所有方法
Method[] methods = curClass.getMethods();
for(Method method:methods){
//看是否存在方法上有change注解的方法
if(method.isAnnotationPresent(Change.class)){
Change chage = method.getAnnotation(Change.class);
String changeKey = chage.key();
if(changeKey!=null&&!"".equals(changeKey)) {
KEY.add(changeKey);
}else {
KEY.add(method.getName());
}
}
}
}
@AfterReturning(returning = "ret", pointcut = "aspect()")
public void doAfterReturning(Object ret) throws Throwable {
List<String> deleteKeys = new ArrayList<String>();
for(String prefix : CACHE_NAMES) {
for(String suffix : KEY) {
//redis中存的key book::10
deleteKeys.add(prefix+JOINT+JOINT+suffix);
}
}
//请求成功,清空带有@Change标签方法的缓存
redisTemplate.delete(deleteKeys);
}
}
3.controller
import java.util.List;
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.RestController;
import com.my.entity.BookEntity;
import com.my.service.BookService;
@RestController
@RequestMapping("book")
public class BookController {
@Autowired
private BookService bookService;
@RequestMapping("/save")
public BookEntity save(@RequestBody BookEntity book) {
return bookService.save(book);
}
@RequestMapping("/getById")
public BookEntity getById(Long id) {
BookEntity book = bookService.getBookById(id);
return book;
}
@RequestMapping("/selectAll")
public List<BookEntity> selectAll(){
return bookService.selectAll();
}
@RequestMapping("/delete")
public String delete(Long id) {
bookService.deleteById(id);
return "success";
}
}
4.service
import java.util.List;
import com.my.entity.BookEntity;
public interface BookService {
//更新或保存
BookEntity save(BookEntity book);
BookEntity getBookById(Long id);
List<BookEntity> selectAll();
void deleteById(Long id);
}
5.service实现
import java.util.List;
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.stereotype.Service;
import com.my.annotation.Change;
import com.my.entity.BookEntity;
import com.my.repository.BookRepository;
import com.my.service.BookService;
@Service
@CacheConfig(cacheNames = "book")//spring自带注解
public class BookServiceImpl implements BookService{
@Autowired
private BookRepository bookRepository;
@CachePut(key = "#p0.id")//spring自带注解
public BookEntity save(BookEntity book) {
BookEntity bookEntity = bookRepository.save(book);
return bookEntity;
}
@Cacheable(key = "#p0")//spring自带注解
public BookEntity getBookById(Long id) {
BookEntity bookEntity = bookRepository.getOne(id);
return bookEntity;
}
@Change//自定义注解
@Cacheable(key="#root.methodName")//spring自带注解
public List<BookEntity> selectAll() {
List<BookEntity> findAll = bookRepository.findAll();
return findAll;
}
@CacheEvict(key = "#p0")//spring自带注解
public void deleteById(Long id) {
bookRepository.deleteById(id);
}
}
6.repository
import org.springframework.data.jpa.repository.JpaRepository;
import com.my.entity.BookEntity;
/**
* extends JpaRepository<T, ID>
* @author MY
*
*/
public interface BookRepository extends JpaRepository<BookEntity, Long>{
}
7.entity
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.Proxy;
@Entity
@Table(name="book")
@Proxy(lazy = false)//注意,该注解一定要加,否则 查询之后,再次从缓存中取值会报错
public class BookEntity implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
@Id//主键
@GeneratedValue(strategy = GenerationType.IDENTITY)//主键由数据库自动生成(主要是自动增长型)
private Long id;
@Column(name="book_name")
private String bookName;
@Column(name="book_author")
private String bookAuthor;
@Column(name="book_count")
private Integer bookCount;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public String getBookAuthor() {
return bookAuthor;
}
public void setBookAuthor(String bookAuthor) {
this.bookAuthor = bookAuthor;
}
public Integer getBookCount() {
return bookCount;
}
public void setBookCount(Integer bookCount) {
this.bookCount = bookCount;
}
}
8.util
import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
@Component
public class RedisUtils {
@Resource(name="redisTemplate")
private RedisTemplate<String, Object> redisTemplate;
//判断是否存在该key
public boolean hasKey(String key) {
return redisTemplate.hasKey(key);
}
//根据对应的class返回key对应的值
public <T> T getValue(String key,Class<T> cls) {
ValueOperations<String, Object> opsForValue = redisTemplate.opsForValue();
Object object = opsForValue.get(key);
return cls.cast(object);
}
//根据对应的key对应的值
public Object getValue(String key) {
ValueOperations<String, Object> opsForValue = redisTemplate.opsForValue();
return opsForValue.get(key);
}
/**
* 将查询结果放入缓存
* 超期时间默认单位为分钟
* @param key key
* @param obj value
* @param time 超期时间
*/
public void setValue(String key, Object obj, int time) {
ValueOperations<String, Object> opsForValue = redisTemplate.opsForValue();
opsForValue.set(key, obj, time, TimeUnit.MINUTES);
}
/**
* 将查询结果放入缓存
* 超期时间默认1小时(60分钟)
* @param key key
* @param obj value
*/
public void setValue(String key, Object obj) {
setValue(key, obj, 60);
}
//删除key
public void deleteKey(String key) {
redisTemplate.delete(key);
}
}
9.启动类
package com.my;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
@SpringBootApplication
@EnableCaching
public class ApplicationMain {
public static void main(String[] args) {
SpringApplication.run(ApplicationMain.class, args);
}
}
遇到的坑
在实体对象加上@Proxy(lazy = false),再删除redis中原有的数据,重新请求就可以了