今天进一步学习了redis的相关知识,希望下面的博客可以给博友们带来帮助。
docker安装redis连接Redis Desktop Manager
启动docker (系统控制ctl:control)
systemctl start docker
查找Docker Hub上的redis镜像
docker search redis
这里我们拉取官方的默认redis镜像
docker pull redis
查询已有的镜像
docker images
使用redis镜像
运行容器
docker run -p 6379:6379 -d redis
命令说明:
-p 6379:6379 : 将容器的6379端口映射到主机的6379端口
查看容器启动情况
docker ps
连接、查看容器,使用redis镜像执行redis-cli命令连接到刚启动的容器,主机IP为127.0.0.1
docker exec -it 43f7a65ec7f8 redis-cli
127.0.0.1:6379> info
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
打开redis可视化工具Redis Desktop Manager
连接本地redis
redis中文网 http://redis.cn/ 可以查看redis命令等
springboot项目使用Cache缓存
一.Cache缓存的作用
大规模的数据库查询操作会成为影响用户使用体验的瓶颈,此时Cache缓存往往是解决这一问题非常好的手段之一。
- 1
1.JSR107
Java Caching定义了5个核心接口,分别是CachingProvider, CacheManager, Cache, Entry 和 Expiry。
- 1
示意图:
CachingProvider定义了创建、配置、获取、管理和控制多个CacheManager。一个应用可 以在运行期访问多个CachingProvider。
CacheManager定义了创建、配置、获取、管理和控制多个唯一命名的Cache,这些Cache 存在于CacheManager的上下文中。一个CacheManager仅被一个CachingProvider所拥有。
Cache是一个类似Map的数据结构并临时存储以Key为索引的值。一个Cache仅被一个 CacheManager所拥有。
Entry是一个存储在Cache中的key-value对。
Expiry 每一个存储在Cache中的条目有一个定义的有效期。一旦超过这个时间,条目为过期 的状态。一旦过期,条目将不可访问、更新和删除。缓存有效期可以通过ExpiryPolicy设置。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
2.Spring缓存抽象
Spring从3.1开始定义了org.springframework.cache.Cache 和org.springframework.cache.CacheManager接口来统一不同的缓存技术; 并支持使用JCache(JSR-107)注解简化我们开发。
Cache接口为缓存的组件规范定义,包含缓存的各种操作集合。
Cache接口下Spring提供了各种xxxCache的实现;如RedisCache,EhCacheCache , ConcurrentMapCache。
每次调用需要缓存功能的方法时,Spring会检查检查指定参数的指定的目标方法是否 已经被调用过;如果有就直接从缓存中获取方法调用后的结果,如果没有就调用方法 并缓存结果后返回给用户。下次调用直接从缓存中获取。
使用Spring缓存抽象时我们需要关注以下两点:
1.、确定方法需要被缓存以及他们的缓存策略
Spring从3.1开始定义了org.springframework.cache.Cache 和org.springframework.cache.CacheManager接口来统一不同的缓存技术; 并支持使用JCache(JSR-107)注解简化我们开发。
Cache接口为缓存的组件规范定义,包含缓存的各种操作集合。
Cache接口下Spring提供了各种xxxCache的实现;如RedisCache,EhCacheCache , ConcurrentMapCache。
每次调用需要缓存功能的方法时,Spring会检查检查指定参数的指定的目标方法是否 已经被调用过;如果有就直接从缓存中获取方法调用后的结果,如果没有就调用方法 并缓存结果后返回给用户。下次调用直接从缓存中获取。
使用Spring缓存抽象时我们需要关注以下两点:
1.确定方法需要被缓存以及他们的缓存策略
2、从缓存中读取之前缓存存储的数据
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
二.几个重要概念&缓存注解
三.SpringBoot中Cache缓存的使用
1.引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
- 1
- 2
- 3
- 4
2.在配置文件中设置属性debug=true,这样就会打印所有的配置报告。
logging:
level:
com.szh.springboot_redis.mapper.*: debug
debug: true
- 1
- 2
- 3
- 4
2.@EnableCaching开启缓存
@MapperScan(basePackages = {"com.szh.springboot_redis.mapper"}) @SpringBootApplication @EnableCaching // 开启缓存注解 public class SpringbootRedisApplication {
public static void main(String[] args) { SpringApplication.run(SpringbootRedisApplication.class, args); }
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
3.@Cacheable缓存注解的使用 (标注在service业务层方法上)
执行流程:先执行@Cacheable注解中的getCache(String name)方法,根据name判断ConcurrentMap中是否有此缓存,如果没有缓存那么创建缓存并保存数据,另外service层的方法也会执行。如果有缓存不再创建缓存,另外service层的方法也不会执行。
总结:先执行@Cacheable----->再执行service层的方法
@Cacheable注解的属性如下:
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Cacheable {
@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 “”;
boolean sync() default false;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
service层代码
第一次查询数据库打印service类方法日志,并把数据保存到Cahce中
第二次传入相同参数不再执行service类方法,不会打印日志,查询的数据直接从缓存中获取
@Service @CacheConfig(cacheNames = "person") //将cacheNames抽取出来 public class PersonService { @Autowired PersonDao personDao;
/*1. @Cacheable的几个属性详解: * cacheNames/value:指定缓存组件的名字 * key:缓存数据使用的key,可以用它来指定。默认使用方法参数的值,一般不需要指定 * keyGenerator:作用和key一样,二选一 * cacheManager和cacheResolver作用相同:指定缓存管理器,二选一 * condition:指定符合条件才缓存,比如:condition="#id>3" * 也就是说传入的参数id>3才缓存数据 * unless:否定缓存,当unless为true时不缓存,可以获取方法结果进行判断 * sync:是否使用异步模式*/ //@Cacheable(cacheNames= "person") //@Cacheable(cacheNames= "person",key="#id",condition="#id>3") @Cacheable(key="#id") public Person queryPersonById(Integer id){ System.out.println("查询"+id+"号员工信息"); Person person=new Person(); person.setId(id); return personDao.query(person); } /** * @CachePut:即调用方法,又更新缓存数据 * 修改了数据库中的数据,同时又更新了缓存 * *运行时机: * 1.先调用目标方法 * 2.将目标方法返回的结果缓存起来 * * 测试步骤: * 1.查询1号的个人信息 * 2.以后查询还是之前的结果 * 3.更新1号的个人信息 * 4.查询一号员工返回的结果是什么? * 应该是更新后的员工 * 但只更新了数据库,但没有更新缓存是什么原因? * 5.如何解决缓存和数据库同步更新? * 这样写:@CachePut(cacheNames = "person",key = "#person.id") * @CachePut(cacheNames = "person",key = "#result.id") */ @CachePut(key = "#result.id") public Person updatePerson(Person person){ System.out.println("修改"+person.getId()+"号员工信息"); personDao.update(person); return person; } /** * @CacheEvict:清除缓存 * 1.key:指定要清除缓存中的某条数据 * 2.allEntries=true:删除缓存中的所有数据 * beforeInvocation=false:默认是在方法之后执行清除缓存 * 3.beforeInvocation=true:现在是在方法执行之前执行清除缓存, * 作用是:只清除缓存、不删除数据库数据 */ //@CacheEvict(cacheNames = "person",key = "#id") @CacheEvict(cacheNames = "person",allEntries=true) public void deletePerson(Integer id){ System.out.println("删除"+id+"号个人信息"); //删除数据库数据的同时删除缓存数据 //personDao.delete(id); /** * beforeInvocation=true * 使用在方法之前执行的好处: * 1.如果方法出现异常,缓存依旧会被删除 */ //int a=1/0; } /** * @Caching是 @Cacheable、@CachePut、@CacheEvict注解的组合 * 以下注解的含义: * 1.当使用指定名字查询数据库后,数据保存到缓存 * 2.现在使用id、age就会直接查询缓存,而不是查询数据库 */ @Caching( cacheable = {@Cacheable(key="#name")}, put={ @CachePut(key = "#result.id"), @CachePut(key = "#result.age") } ) public Person queryPersonByName(String name){ System.out.println("查询的姓名:"+name); return personDao.queryByName(name); }
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
springboot项目整合 Redis 实现缓存操作
缓存大致流程
springboot-mybatis-redis 案例
pom.xml 依赖配置:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <!-- Spring Boot 启动父依赖 --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.5.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.szh</groupId> <artifactId>springboot_redis</artifactId> <version>0.0.1-SNAPSHOT</version> <name>springboot_redis</name> <!--整合 Mybatis 并使用 Redis 作为缓存--> <description>Demo project for Spring Boot</description>
<properties> <java.version>1.8</java.version> </properties> <dependencies> <!-- <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency>--> <!-- Spring Boot Reids 依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.0.1</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> <version>2.1.8.RELEASE</version> <scope>compile</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
</project>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
application.yml 应用配置文件,增加 Redis 相关配置
server:
port: 8080
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/first?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
username: root
password: root
redis:
host: 192.168.72.129 ##Redis服务器地址
port: 6379 ## Redis服务器连接端口
database: 0 ## Redis数据库索引(默认为0)
logging:
level:
com.szh.springboot_redis.mapper.*: debug
debug: true
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
实体类这里就不细写了,各位小伙伴就根据自己相应的数据库来编写吧。
Service业务逻辑层
package com.szh.springboot_redis.service;
import com.szh.springboot_redis.pojo.Students;
import java.util.List;
public interface StudentService {
/**
* 查询所有信息
* @return
*/
List<Students> findAllStudnet();
/**
* 删除指定信息
* @param id
* @return
*/
int delStudent(Integer id);
/**
* 修改指定信息
* @param students
* @return
*/
int updateStudent(Students students);
/**
* 根据id查询
* @param id
* @return
*/
Students findStudentById(Integer id);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
业务逻辑实现类 StudnetServiceImpl .java:
package com.szh.springboot_redis.service.impl;
import com.szh.springboot_redis.mapper.StudentMapper;
import com.szh.springboot_redis.pojo.Students;
import com.szh.springboot_redis.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class StudnetServiceImpl implements StudentService {
@Autowired
private StudentMapper studentMapper;
@Autowired
private RedisTemplate redisTemplate;
/**
* 查询所有信息
* @return
*/
@Override
public List<Students> findAllStudnet() {
String key = "student";
ValueOperations<String, List<Students>> operations = redisTemplate.opsForValue();
// 缓存存在
boolean hasKey = redisTemplate.hasKey(key);
if (hasKey) {
List<Students> students = operations.get(key);
return students;
}else {
// 从 DB 中获取城市信息
List<Students> students = studentMapper.findAllStudnet();
// 插入缓存
operations.set(key, students);
return students;
}
}
/**
* 根据id查询信息
* @param id
* @return
*/
@Override
public Students findStudentById(Integer id) {
String key = "city_" + id;
ValueOperations<String, Students> operations = redisTemplate.opsForValue();
// 缓存存在
boolean hasKey = redisTemplate.hasKey(key);
if (hasKey) {
Students students = operations.get(key);
return students;
}else {
// 从 DB 中获取城市信息
Students students = studentMapper.findStudentById(id);
// 插入缓存
operations.set(key, students);
return students;
}
}
/**
* 删除指定信息
* @param id
* @return
*/
@Override
public int delStudent(Integer id) {
int ret = studentMapper.delStudent(id);
// 缓存存在,删除缓存
String key = "studnet_" + id;
boolean hasKey = redisTemplate.hasKey(key);
if (hasKey) {
redisTemplate.delete(key);
}
return ret;
}
/**
* 修改指定信息
* @param students
* @return
*/
@Override
public int updateStudent(Students students) {
int ret = studentMapper.updateStudent(students);
// 缓存存在,删除缓存
String key = "students_" + students.getSid();
boolean hasKey = redisTemplate.hasKey(key);
if (hasKey) {
redisTemplate.delete(key);
}
return ret;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
Controller层
StudentController.java类
package com.szh.springboot_redis.controller;
import com.szh.springboot_redis.pojo.Students;
import com.szh.springboot_redis.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
public class StudentController {
@Autowired
StudentService studentService;
/**
* 查询所有信息
* @return
*/
@GetMapping("/select")
public List<Students> findStudents(){
List<Students> students = studentService.findAllStudnet();
return students;
}
/**
* 根据id查询信息
* @param id
* @return
*/
@GetMapping("/select/{id}")
public Students selStudentId(@PathVariable("id") Integer id){
Students student = studentService.findStudentById(id);
return student;
}
/**
* 修改信息
* @param student
* @return
*/
@PutMapping("/update")
public int update(Students student) {
return studentService.updateStudent(student);
}
/**
* 删除信息
* @param id
* @return
*/
@DeleteMapping("delete")
public int delete(Integer id) {
return studentService.delStudent(id);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
修改springboot中redis配置中的修改RedisTemplate 默认的序列化规则,将缓存序列化。
配置config文件
RedisConfig.java类
package com.szh.springboot_redis.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig{
@Bean
@SuppressWarnings(“all”)
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(factory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key也采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
运行
测试
第一次查询是用sql语句从mysql数据库中查询出数据
第二次直接从缓存中拿数据
redis的可视化工具Redis Desktop Manager查看
大功告成!
希望本博客可以给大家带来帮助。
转载至-CSDN*丢了微笑该如何释怀
</div>
<link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-258a4616f7.css" rel="stylesheet">
</div>