1.SpringDataRedis
一.SpringDataRedis简介
- SpringDataRedis 属于Spring Data 家族一员,用于对redis的操作进行封装的框架
- Spring Data ----- Spring 的一个子项目。Spring 官方提供一套数据层综合解决方案,用于简化数据库访问,支持NoSQL和关系数据库存储。包括Spring Data JPA 、SpringData Redis 、SpringDataSolr 、SpringDataElasticsearch 、Spring DataMongodb 等框架。
二.SpringDataRedis快速入门
- 准备工作
- 构建Maven工程 SpringDataRedisDemo 引入Spring相关依赖、JUnit依赖、Jedis和SpringDataRedis依赖
- 在src/main/resources下创建properties文件夹,建立redis-config.properties
maxIdle :最大空闲数
maxWaitMillis: 连接时的最大等待毫秒数 - 在src/main/resources下创建spring文件夹,创建applicationContext-redis.xml
- 值类型操作
- Set类型操作
- List类型操作
- 右压栈 后添加的对象排在后边
运行结果:[刘备, 关羽, 张飞] - 左压栈 后添加的对象排在前边
运行结果:[张飞, 关羽, 刘备] - 根据索引查询元素
- 移除指定个数的值
- 右压栈 后添加的对象排在后边
- Hash类型操作
- 存入值
- 提取所有的KEY
运行结果:[a, b, c, d] - 提取所有的值
- 根据KEY提取值
- 根据KEY移除值
- 存入值
- ZSet类型操作
zset是set的升级版本,它在set的基础上增加了一格顺序属性,这一属性在添加元素的同时可以指定,每次指定后,zset会自动重新按照新的值调整顺序。可以理解为有两列的mysql表,一列存储value,一列存储分值。- 存值 ,指定分值
- 查询,由低到高
- 查询,由高到低
- 增加分数
- 查询值和分数
TypedTuple是值与分数的封装。
- 存值 ,指定分值
- 过期时间设置
以值类型为例:存值时指定过期时间和时间单位
2.缓存穿透、缓存击穿、缓存雪崩
一.缓存穿透
- 缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,如发起为id为“-1”的数据或id为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大。如下面这段代码就存在缓存穿透的问题。
- 解决方案:
- 接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截;
- 从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-0。这样可以防止攻击用户反复用同一个id暴力攻击。代码举例:
- 使用缓存预热
缓存预热就是将数据提前加入到缓存中,当数据发生变更,再将最新的数据更新到缓存。后边我们就用缓存预热的方式实现对分类导航、广告轮播图等数据的缓存。
二.缓存击穿
- 缓存击穿是指缓存中没有但数据库中有的数据。这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力。
以下代码可能会产生缓存击穿: - 解决方案:
1.设置热点数据永远不过期。
2.缓存预热
三.缓存雪崩
- 缓存雪崩是指缓存数据大批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至down机。和缓存击穿不同的是,缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。
- 解决方案:
1.缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
2.设置热点数据永远不过期。
3.使用缓存预热
3.商品分类导航缓存
一.需求分析
- 为了提升首页的加载速度,减轻数据库访问压力,我们将首页的商品分类导航数据加载在缓存中。
二.实现思路
- 为了避免缓存穿透、击穿等问题,我们采用缓存预热的方式实现对分类导航数据的缓存。
- 考虑到商品分类导航数据不经常变动,所以我们不设置过期时间。
三.通用模块整合spring data redis
- qingcheng_common_service引入依赖
- qingcheng_common_service新增配置文件 redis-config.properties
maxWait:连接池中连接用完时,新的请求等待时间,毫秒
maxIdle: 最大闲置个数 - qingcheng_common_service新增spring配置文件applicationContext-redis.xml
- qingcheng_common_service工程新增枚举
四.商品分类加载到缓存
- 服务接口CategoryService新增方法定义
- CategoryServiceImpl实现此方法
- qingcheng_service_goods工程新增类
实现InitializingBean接口的类会在启动时自动调用。
五.查询商品分类缓存
- 修改CategoryServiceImpl的findCategoryTree方法 ,直接从缓存中提取数据。
六.更新商品分类缓存
- 修改CategoryServiceImpl的增删改方法,在增删改后重新加载缓存
4.广告轮播图缓存
一.需求分析
- 为了提升首页的加载速度,减轻数据库访问压力,我们将首页的广告轮播图数据加载在缓存中。
二.实现思路
- 使用“缓存预热”的方式实现
广告数据不只是轮播图,我们可以使用hash来存储广告数据。
三.广告数据加载到缓存
- AdService新增方法定义
- AdServiceImpl方法实现
- qingcheng_service_business工程新增类
四.查询广告缓存
- 修改AdServiceImpl的findByPosition方法
五.更新广告缓存
- 修改AdServiceImpl的增删改方法
5.商品详细页价格缓存
一.需求分析
- 我们已经将商品的信息生成为静态页面,但是商品价格经常变动,如果每次价格变动后都对静态页重新生成会影响服务器性能。所以,对于商品价格,我们采用异步调用的方式来进行客户端渲染。
二.实现思路
- 商品服务启动后加载全部价格数据到缓存。使用hash存储,skuID作为小KEY
- 从缓存从查询商品价格,封装为controller,并设置可跨域调用
- 什么叫跨域?
当协议、子域名、主域名、端口号中任意一个不相同时,都算作不同域。不同域之间相互请求资源,就算作“跨域”。
JavaScript出于安全方面的考虑,不允许跨域调用其他页面的对象。那什么是跨域呢,简单地理解就是因为JavaScript同源策略的限制,a.com域名下的js无法操作b.com或是c.a.com域名下的对象。 - 如何解决跨域问题?我们使用CORS实现跨域。
CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resourcesharing)。它允许浏览器向跨源服务器,发出 XMLHttpRequest 请求,从而克服了AJAX只能同源使用的限制。使用非常简单,只需要在controller类上添加一个 @CrossOrigin注解即可
- 什么叫跨域?
- 修改商品详细页模板,使用ajax读取价格,并进行客户端渲染。
三.价格数据加载到缓存
- SkuService接口新增方法定义
- SkuServiceImpl类新增方法
- 修改InitService类
四.查询价格缓存
- SkuService新增方法定义
- SkuServiceImpl实现findPrice方法
- qingcheng_web_portal工程新增类
- 前端代码(修改模板):
(1)将vue.js axios.js 放到我们html输出文件夹下的js文件夹中。
(2)修改qingcheng_web_portal工程的模板 item.html
th:inline 定义js脚本可以使用变量 js脚本的变量用 /*[[${ }]]*/ 渲染
(3)修改qingcheng_web_portal工程的模板 item.html ,添加 <div id="app">...
</div> ,并将价格修改为vue表达式
五.更新价格缓存
- SkuService接口新增方法定义
- SkuServiceImpl类新增方法
- SpuServiceImpl类引入SkuService
- 修改SpuServiceImpl类saveGoods方法,在SKU列表循环体中添加代码
六.删除价格缓存
- SkuService新增方法定义
- SkuServiceImpl新增方法实现
- 修改SpuServiceImpl的delete方法,新增代码逻辑