Spring Cache+Redis 缓存数据
缓存:为了提高查询速度
适合做缓存的场景:不经常修改数据,固定的数据,经常查询的数据。
Spring Cache
是一个非常优秀的缓存组件,自Spring3.1起,提供了类似于@Transactional注解事务的注解Cache支持,且提供了Cache抽象,方便切换各种低层Cache(如:redis);
使用Spring Cache的好处:
1.提供基本的Cache抽象,方便切换各种低层Cache。
2.通过注解Cache可以实现类似于事务一样,缓存逻辑透明的应用到我们的业务代码上,且只需要更少的代码就可以完成;
3.提供事务回滚的时也自动回滚缓存;
4.支持比较复杂的缓存逻辑;
Redis
1.是什么:REmote DIctionary Server(远程字典服务器)
redis安装Windows下
1.1解压redis包
1.2.打开cmd指令窗口
1.3.输入你刚才解压的文件路径
1.4.然后输入redis-server redis.windows.conf 命令
接下来部署Redis为windows下的服务 首先关掉上一个窗口再打开一个新的cmd命令窗口
然后输入指令redis-server --service-install redis.windows.conf
redis常用指令
卸载服务:redis-server --service-uninstall
开启服务:redis-server --service-start
停止服务:redis-server --service-stop
切换到解压的redis目录,利用cmd打开
输入redis-cli
2.linux系统中安装redis
2.1 安装docker
#卸载旧版本
sudo yum remove docker docker-common container-selinux docker-selinux docker-engine
sudo yum remove -y docker-*
#查询版本:无则说明卸载完毕
docker version
#安装最新docker
sudo yum update
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
sudo yum makecache fast
sudo yum install docker-ce docker-ce-cli containerd.io
#查询docker版本
yum list docker-ce --showduplicates | sort -r
#选择版本安装
yum install -y docker-ce-[docker版本]
#启动docker
sudo systemctl start docker
#搜索redis
docker search redis
#docker 拉redis镜像
docker pull redis:latest
#查询docker镜像是否有redis
docker pull redis:latest
#启动redis
docker run -itd --name redis -p 6379:6379 redis
#查看是否启动完成
docker ps
#客户端登录redis
docker exec -it redis /bin/bash
redis-cli
#停止redis
docker stop redis
#删除redis
docker rm redis
#获取docker中所有容器id
docker container ls -a
#根据容器中id停止相应的镜像
docker container stop container_ID
#删除redis镜像前应先停止redis
docker container rm CONTAINER_ID //或CONTAINER_NAME
#批量获取容器ID
docker container ls -a -q
#批量获取镜像ID
docker image ls -a -q
#批量停止容器
docker container stop $(docker container ls -a -q)
#批量删除容器
docker container rm $(docker container ls -a -q)
#通过image的id来指定删除镜像
docker rmi <image id>
#想要删除untagged images,也就是那些id为<None>的image的话可以用
docker rmi $(docker images | grep "^<none>" | awk "{print $3}")
#要删除全部images
docker rmi $(docker images -q)
#访问容器
docker exec -it redis bash
#使用redis-cli访问容器内redis
docker exec -it redis redis-cli
#开始测试redis,进入
redis-cli
#添加key value
set A 1
#通过key 查询value
get A
#查询所有key
keys *
#删除key
del A
NoSQL
mysql主从分离:买家一个库。卖家一个库.
NoSQL 意为”不仅仅是sql“;泛指非关系型数据库:经典的公式:ACID(原则一致,独立隔离);这类型的数据库存储不需要固定的模式。无需多余操作就可以横向扩展。
Nosql数据库具有非常高的读写特性。
NOSQL无需事先为要存储的数据建立字段,随时可以存储自在定义的数据格式。而关系数据库里。
增删字段是一件非常麻烦的事情。如果是非常大数据量的表,增加字段简直就是一个噩梦。
RDBMS(关系型数据库)VS NoSQL
RDBMS:1.结构化查询语言(SQL)
NoSQL
注意:NoSQL能做什么:易扩展,大数据量高性能,多样灵活的数据模型,传统RDBMS VS NoSQL
1.不仅仅是sql;
Nosql 中的3v+3高 :
1.大数据时代的3V:海量Volume;多样Variety;实时Velocity
2.互联网需求的3高:高并发;高可扩(横向扩展:一台机器干不了,一排干);高性能(单点故障);
去IOE:去除IBM小型机、Oracle数据库及EMC存储设备
负载均衡:
分布式和集群的简介:
分布式:不痛的多台服务器上面部署不痛的服务模块(工程),他们之间通过Rpc/Rmi之间通信和调用,对外提供服务和组内协作。
集群:不同的多台服务器上面部署相同的服务模块,通过分布式调用软件进行统一的调度,对外提供服务和访问。
是完全开源免费的,用C语言编写的,遵守BSD协议,是一个高性能的(key/value)分布式内存数据库,基于内存运行
并支持持久化的NoSQL数据库,是当前最热门的NoSql数据库之一,
也被人们称为数据结构服务器
Redis三种特性
1.Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用
2.Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储
3.Redis支持数据的备份,即master-slave模式的数据备份
Redis能干嘛:
内存存储和持久化:redis支持异步将内存中的数据写到硬盘上,同时不影响继续服务
取最新N个数据的操作,如:可以将最新的10条评论的ID放在Redis的List集合里面
模拟类似于HttpSession这种需要设定过期时间的功能
发布、订阅消息系统
定时器、计数器
hashset hashmap
hashset的底层就是hashmap
Redis启动后杂项基础知识讲解
默认16个数据库,类似数组下表从零开始,初始默认使用零号库
> DBsize 查看当前数据库的key的数量
> SELECT 命令切换数据库 (eg:select 1 切换到第二个数据库)
> FLUSHDB 清空当前数据库
> FLUSHALL 清空所有的数据库
Redis五大数据类型:
1.String(字符串); 2.list(列表);3.Set (集合);4.Zset(sorted set:有序集合);5.hash 类似于Java中的map
redis的String可以包含任何数据,比如jpg图片或者序列化的对象。
redis列表是简单的字符串列表,按照插入顺序排序
redis的set是String类型的无序集合,它是通过hashtable实现的
1.项目集成spring cache+redis
因为缓存也是公共使用,所有的Service模块都有可能使用缓存,随意把依赖于部分配置加在service_util模块,这样其他service模块都可以使用了
1.1.service_util添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--spring2.x集成redis所需要的common-pool2-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.6.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
1.2 配置类
package com.zhsh.cyz.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
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.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.lang.reflect.Method;
import java.time.Duration;
/**
* @description:
* @author:cyz
* @time:2021/10/25 0025
*/
@Configuration
//开启缓存
@EnableCaching
public class RedisConfig {
/**
*@description 自定义key规则
*@params
*@return
*@author cyz
*@Date 2021/10/25 0025
*/
@Bean
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params){
StringBuilder sb=new StringBuilder();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj:params) {
sb.append(obj.toString());
}
return sb.toString();
}
};
}
/**
*@description 设置redisTemplate规则
*@params redisConnectionFactory
*@return
*@author cyz
*@Date 2021/10/25 0025
*/
public RedisTemplate<Object,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
RedisTemplate<Object,Object> redisTemplate=new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer=new Jackson2JsonRedisSerializer(Object.class);
//解决查询缓存转换异常的问题
ObjectMapper om=new ObjectMapper();
//指定要序列化的域,field,get和set以及修饰符范围,ANY是都有包括private和public
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
//指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
//序列号key value
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
/**
*@description 设置CacheManager缓存规则
*@params factory
*@return
*@author cyz
*@Date 2021/10/25 0025
*/
public CacheManager cacheManager(RedisConnectionFactory factory){
RedisSerializer<String> redisSerializer=new StringRedisSerializer();
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);
//配置序列化(解决乱码问题),过期时间600秒
RedisCacheConfiguration config=RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofSeconds(600))
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
.disableCachingNullValues();
RedisCacheManager cacheManager=RedisCacheManager.builder(factory)
.cacheDefaults(config)
.build();
return cacheManager;
}
}
说明:
@EnableCaching:标记注解@EnableCaching,开启缓存,并配置Redis缓存管理器,@EnableCaching注解触发后置处理器,检查每一个Spring bean的public方法是否存在缓存注解,如果找到这样的一个注释,自动创建一个代理拦截方法调用和处理相应的缓存行为。
1.3 service_cmn配置文件application.properties添加redis
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.database=0
spring.redis.timeout=1800000
spring.redis.lettuce.pool.max-active=20
spring.redis.lettuce.pool.max-wait=-1
#最大阻塞等待时间(负数代表没有限制)
spring.redis.lettuce.pool.max-idle=5
spring.redis.lettuce.pool.min-idle=0
# 设置缓存默认超过期时间为30秒
spring.cache.redis.time-to-live.seconds=10
spring.cache.redis.use-key-prefix=true
spring.cache.redis.key-prefix=dev
spring.cache.redis.cache-null-values=false
spring.cache.redis.time-to-live=20s
2.使用spring Cahce
2.1常用缓存标签
2.1.1缓存标签@Cacheable
根据方法对其返回结果进行缓存,下次请求时,如果缓存存在,则直接读取缓存数据返回,如果缓存不存在,则执行方法,并把返回的结果存入缓存中,一般用在查询方法上。
查看源码,属性值如下:
属性/方法名 解释
value 缓存名,必填,它指定了你的缓存存放在哪块命名空间
cacheNames 与value差不多,二选一即可
key 可选属性,可以使用SpEL标签自定义缓存的key
2.1.2缓存@CachePut(添加一个数据后,将会把数据同步到缓存中)
使用该注解标志的方法,每次都会执行,并将结果存入指定的缓存中。其他方法可以直接从响应的缓存中读取缓存数据,而不需要再去查询数据库,一般用在新增方法上。
查看源码,属性值如下:
属性/方法名 解释
value 缓存名,必填,它指定了你的缓存存放在哪块命名空间
cacheNames 与value差不多,二选一即可
key 可选属性,可以使用SpEL标签自定义缓存的key
2.1.3缓存@CacheEvict
使用该注解标志的方法,会清空指定的缓存。一般用在更新或者删除方法上
查看源码,属性值如下:
属性/方法名 解释
value 缓存名,必填,它指定了你的缓存存放在哪块命名空间
cacheNames 与value差不多,二选一即可
key 可选属性,可以使用SpEL标签自定义缓存的key
allEntries 是否清空所有缓存,默认为false。如果指定为true,则方法调用后将立即清空所有的缓存
beforeInvocation 是否在方法执行前就清空,默认为false,如果指定为true,则在方法执行前就会清空缓存。
直接在service层实现类中添加相应的注解即可完成对数据的缓存,缓存的key值为value值+实现的方法
/**
* @description: 数据字典控制类
* @author:cyz
* @time:2021/10/22 0022
*/
@Cacheable(value = "dict",keyGenerator = "keyGenerator")
@Override
public List<AreaCode> FindDataById(Long id) {
QueryWrapper<AreaCode> wrapper=new QueryWrapper<>();
wrapper.eq("pid",id);
List<AreaCode> list=baseMapper.selectList(wrapper);
for (AreaCode ac:list) {
Long acId = ac.getId();
boolean isChild=this.isChildren(acId);
ac.setHasChildren(isChild);
}
return list;
}
//导入数据功能
@Override
@CachePut(value="dict")
public void importData(MultipartFile file) {
try {
//读取file流,同时需要进行监听配置,在监听配置中将数据写入数据库中
EasyExcel.read(file.getInputStream(),DataVo.class,new DataListener(baseMapper)).sheet().doRead();
}catch(Exception e){
e.printStackTrace();
}
}
//删除某一条数据
@Override
@CacheEvict(value="dict",allEntries=true)
public void delData(String id){
baseMapper.deldatabyId(id);
}