开发辅助三(缓存Redisson分布式锁+分页插件)

缓存

缓存穿透:查询一个不存在的数据,由于缓存不命中,将大量查询数据库,但是数据库也没有此记录。
没有将这次查询的null写入缓存,导致了这个不存在的数据每次请求都要到存储层查询,失去了缓存的意义。
解决:null结果缓存,并加入短暂的过期事件

缓存雪崩:设置缓存时采用了相同的过期时间,导致缓存存在某一时刻同时失效,请求全部转发到DB,DB瞬时压力过重
解决:原有的失效时间基础上增加一个随机值,这样缓存的过期时间重复率就会降低。

缓存击穿:对于一些设置了过期时间的key,如果这些key在某些时间点高并发地访问,同时正好失效,那么所有的压力都会到数据库上。
解决:大量并发只让一个去查,其他人等待,查到以后释放锁,其他人获取到锁,先查缓存,就有数据,不用去数据库。
将redis作为缓存工具
在这里插入图片描述

①、模块中导入依赖,并且配置文件application.yml添加reids连接信息IP和端口

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

②、Service业务类中使用

@Autowired
private StringRedisTemplate redisTemplate;@Override
public Map<String,List<Categlo2Vo>> getCatelogJson(){String catelogJSON = redisTemplate.opsForValue().get("catelogJSON");if(!StringUtils.isEmpty(catalogJSON)){//如果redis不存在,则从数据库中查找,然后将数据库查找的结果放入缓存redis中Map<String,List<Catelog2Vo>> catalogJsonFromDb = getCatalogJsonFromDb();return catalogJsonFromDb;}//如果缓存中存在json,则需要转为对象Map<String,List<Catelog2Vo>> result = JSON.parseObject(catalogJSON,new TypeReference<Map<String,List<Catelog2Vo>>>(){});return result;
}//查询数据库
public Map<String,List<Catelog2Vo>> getCatalogJsonFromDb(){synchronized(this){//得到锁以后,应该再去缓存确定一次,如果没有才需要继续查询String catalogJSON = redisTemplate.opsForValue().get("catalogJSON");if(!StringUtils.isEmpty(catalogJSON)){Map<String,List<Catelog2Vo>> result = JSON.parseObject(catalogJSON,new TypeReference<Map<String,List<Catelog2Vo>>>(){});return result;}//查询数据库的业务逻辑……//...//缓存中以json类型存储可以跨平台使用,所以将对象转为json,并放到缓存中String s = JSON.toJSONString(catalogJsonFromDb);redisTemplate.opsForValue().set("catalogJSON",s,1,TimeUnit.DAY);return parent_cid;}}

产生堆外异常OutOfDirectMemoryError
SpringBoot2.0以后默认使用lettuce作为操作redis的客户端,使用netty进行网络通信
lettuce的bug导致netty堆外内存溢出,-Xmx300m
解决方案:①、升级lettuce客户端 ②、切换jedis

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId><exclusions><exclusion><groupId>io.lettuce</groupId><artifactId>lettuce-core<artifactId></exclusion></exclusions>
</dependency>
<dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId>
</denpendency>

分布式锁

redis命令

set locl 1111 NXset lock 1111 EX 300 NX #占坑的同时添加了过期时间

①、若查询数据库业务中出现异常,导致delete锁无法执行,出现死锁情况,则通过添加expire过期时间来释放锁

public Map<String,List<Catelog2Vo>> getCatalogJsonFromDbWithRedisLock(){//占分布式锁(如果不存在,即设置)Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock","111");if(lock){//加锁成功,执行业务redisTemplate.expire("lock",30,TimeUnit.SECONDS);//防止查询数据库业务中出现异常导致的死锁Map<String,List<Catelog2Vo>> dataFromDb = getDataFromDb();//即使业务出现异常,还会删除锁redisTemplate.delete("lock");return dataFromDb}else{ //加锁失败//重试return getCatalogJsonFromDbWithRedisLock();}}

在这里插入图片描述
②、若在执行过期时间的时候出现异常,造成无法释放锁

public Map<String,List<Catelog2Vo>> getCatalogJsonFromDbWithRedisLock(){Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock","1111",300,Time.SECONDS);//占锁的时候同时设置过期时间if(lock){Map<String,List<Catelog2Vo>> dataFromDb = getDataFromDb();//即使业务出现异常,还会删除锁redisTemplate.delete("lock");return dataFromDb}else{return getCatalogJsonFromDbWithRedisLock();}
}

在这里插入图片描述

③、删除锁导致将其他线程锁也删除,通过判断先获取自己的锁值,然后在删除自己的锁

public Map<String,List<Catelog2Vo>> getCatalogJsonFromDbWithRedisLock(){String uuid = UUID.randomUUID().toString();Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock",uuid,300,Time.SECONDS);//占锁的时候同时设置过期时间if(lock){Map<String,List<Catelog2Vo>> dataFromDb = getDataFromDb();String lockValue = redisTemplate.opsForValue().get("lock");if(uuid.equals(lockValue)){redisTemplate.delete("lock");}return dataFromDb;}else{return getCatalogJsonFromDbWithRedisLock();}
}

在这里插入图片描述

④、如果判断之后出现锁过期,而其他线程设置了锁,那么删除的依然是其他线程的锁(加锁、解锁都保证原子性)

public Map<String,List<Catelog2Vo>> getCatalogJsonFromDbWithRedisLock(){String uuid = UUID.randomUUID().toString();Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock",uuid,300,Time.SECONDS);//占锁的时候同时设置过期时间if(lock){Map<String,List<Catelog2Vo>> dataFromDb;try{dataFromDb = getDataFromDb();}finally{//通过lua脚本解锁String script = "if redis.call('get',KEYS[1] == ARGV[1] then return redis.call('del',KEYS[1])) else return 0 end";Long lock1 = redisTemplate.execute(new DefaultRedisScript<Long>(script,Integer.class),Arrays.asList("lock"),uuid);}return dataFromDb;}else{return getCatalogJsonFromDbWithRedisLock();}
}

在这里插入图片描述

分布式锁Redisson

①、导入依赖

<dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.12.0</version>
</dependency>

②、配置类

@Configuration
public class MyRedissonConfig{@Bean(destroyMethod="shutdown")public RedissonClient redisson() throws IOException{Config config = new Config();/**Redis集群模式config.useClusterServers().addNodeAddress("127.0.0.1:7004","127.0.0.1:7001");*///Redis单节点模式config.useSingleServer().setAddress("redis://192.168.56.10:6379");RedissonClient redissonClient = Redisson.create(config);return redissonClient;}
}

③、使用

@Autowired
private RedissonClient redisson;public Map<String,List<Catelog2Vo>> getCatalogJsonFromDbWithRedissonLock(){//获取锁,锁的粒度越小越好RLock lock = redisson.getLock("catalogJson-lock");lock.lock();Map<String,List<Catelog2Vo>> dataFromDb;try{dataFromDb = getDataFromDb();}finally{lock.unlock();}return dataFromDb;
}

缓存一致性

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

整合SpringCache

①、引入依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

②、配置application.properties,配置使用redis作为缓存

spring.cache.type=redis
spring.cache.redis.time-to-live=1000 #设置过期时间,以毫秒为单位
spring.cache.redis.key-prefix=CACHE_
spring.cache.redis.use-key-prefix=true#是否缓存空值(防止缓存穿透)
spring.cache.redis.cache-null-value=true

③、使用

先在启动类开启缓存注解 @EnableCaching

Service实现的业务类中:

@Cacheable(value={"category"},key="'level1Categorys'") //当前方法的结果需要缓存,如果缓存中有,方法不用调用
@Override
public List<CategoryEntity> getLevel1Categorys(){Long l = System.currentTimeMllis();List<CategoryEntity> categoryEntities = baseMapper.selectList();return categoryEntities;
}@CacheEvict(value="category",key="getLevel1Categorys")//修改时,删除缓存
@Transactional
@Override
public void updateCascade(CategoryEntity category){}

自定义缓存配置类

@EnableConfigurationProperties(CacheProperties.class) //开启和配置文件的绑定功能,使得配置文件的内容生效
@Configuration
@EnableCaching
public class MyCacheConfig{/**第一种方式:直接从容器的配置文件获取第二种方式:将其作为方法参数(如下方法的参数)*/
//	@Autowired
//	CacheProperties cacheProperties;//从容器中获取配置@Beanpublic RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties){RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();//对key和value进行序列化config = config.serializeKeysWith(RedisSerializetionContext.SerializationPair.fromSerializer(new StringRedisSerializer()));config = config.serializeValuesWith(RedisSerializetionContext.SerializationPair.fromSerializer(new StringRedisSerializer(new GenericJackson2JsoRedisSerializer()));//将配置文件中的所有配置生效CacheProperties.Redis redisProperties = cacheProperties.getRedis();if(redisProperties.getTimeToLive()!=null){config = config.entityTtl(redisProperties.getTimeToLive());}if(redisProperties.getKeyPrefix()!=null){config = config.prefixKeysWith(redis.getKeyPrefix());}if(!redisProperties.isCacheNullValues()){config = config.disableCachingNullValues();}if(!redisProperties.isUserKeyPrefix){config = config.disableKeyPrefix();}return config;}
}

分页插件

查询用户分页显示功能

①、myatis分页插件依赖

<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId>
</dependency>

②、配置文件spring-persist-mybtis.xml

<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactory"><property name="configLocation" value="classpath:mybatis-config.xml"/><property name="mapperLocations" value="classpath:mybatis/mapper/*Mapper.xml"/><property name="dataSource" ref="dataSource"/><!--配置插件--><property name="plugins"><array><!--分页插件--><bean class="com.github.pagehelper.PageHelper"><property name="properties"><props><!--数据库方言--><prop key="dialect">mysql</prop><!--配置页码的合理化修正,在1~总页数之间修正页码--><prop key="reasonable">true</prop></props></property></bean></array></property>
</bean>

③、Mapper文件和Mapper接口

<select id="selectAdminByKeyword" resultMap="BaseResultMap">select id,login_acct,user_pswd,user_name,email,create_timefrom t_adminwhere login_acct like concat("%",#{keyword},"%") or user_name like concat("%",#{keyword},"%") oremail like concat("%",#{keyword},"%")
</select>
List<Admin> selectAdminByKeyword(String keyword);

④、service实现

@Override
public PageInfo<Admin> getPageInfo(String keyword,Integer pageNum,Integer pageSize){//调用PageHelper静态方法开启分页功能PageHelper.startPage(pageNum,pageSize);//执行查询List<Admin> list = adminMapper.selectAdminByKeyword(keyword);//封装到PageInfo对象中return new PageInfo<>(list);
}

⑤、Controller

@RequestMapping("/admin/get/page.html")
public String getPageInfo(@RequestParam(value="keyword",defaultValue="")String keyword,@RequestParam(value="pageNum",defaultValue="1")Integer pageNum,@RequestParam(value="pageSize",defaultValue="5")Integr pageSize,ModelMap modelMap){PageInfo<Admin> pageInfo = adminService.getPageInfo(keyword,pageNum,pageSize);modelMap.addAttribute(CrowdConstant.ATTR_NAME_PAGE_INFO,pageInfo);return "admin-page"
}

⑥、页面中循环遍历

<c:if test="${empty requestScope.pageInfo.list}"><tr><td colspan="6" align="center">没有查询到你要的数据</td></tr>
</c:if>
<c:if test="${!empty requestScope.pageInfo.list}"><c:forEach items="${requestScope.pageInfo.list}" var="admin"><c:forEach>
</c:if>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/592352.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

复试 || 就业day02(2024.01.02)项目一

文章目录 前言最小二乘法的推导使用正规方程求解 y w x b ywxb ywxb多元线性回归 y w 1 x 1 w 2 x 2 b yw1x1w2x2b yw1x1w2x2b总结 前言 &#x1f4ab;你好&#xff0c;我是辰chen&#xff0c;本文旨在准备考研复试或就业 &#x1f4ab;本文内容来自某机构网课&#xff…

Debezium发布历史43

原文地址&#xff1a; https://debezium.io/blog/2018/12/05/automating-cache-invalidation-with-change-data-capture/ 欢迎关注留言&#xff0c;我是收集整理小能手&#xff0c;工具翻译&#xff0c;仅供参考&#xff0c;笔芯笔芯. 通过更改数据捕获自动使缓存失效 2018 年…

文本表示模型简介

文本是一类非常重要的非结构化数据&#xff0c;如何表示文本数据一直是机器学习领域的一个重要研究方向。那么有哪些文本表示模型&#xff1f;以及它们各有什么优缺点&#xff1f; 1. 常见的文本表示模型 1.1. 词袋模型和N-gram模型 最基础的文本表示模型是词袋模型。顾名思…

QML —— RadioButton的两个经典示例(附完整源码)

示例1-效果 示例2-效果 实例1 - 源码 import QtQuick 2.12 import QtQuick.Window 2.12import QtQuick.Layouts 1.12 import QtQuick.Controls 2.5Window {visible: truewidth: 640height: 480title: qsTr("Hello World")Text{id: classNametext: qsTr("--&quo…

2024年美赛数学建模ABCDEF题思路选题分析

文章目录 1 赛题思路2 美赛比赛日期和时间3 赛题类型4 美赛常见数模问题5 建模资料 1 赛题思路 (赛题出来以后第一时间在CSDN分享) https://blog.csdn.net/dc_sinor?typeblog 2 美赛比赛日期和时间 比赛开始时间&#xff1a;北京时间2024年2月2日&#xff08;周五&#xff…

Redis(二)数据类型

文章目录 官网备注十大数据类型StringListHashSetZSetBitmapHyperLogLog&#xff1a;GEOStreamBitfield 官网 英文&#xff1a;https://redis.io/commands/ 中文&#xff1a;http://www.redis.cn/commands.html 备注 命令不区分大小写&#xff0c;key区分大小写帮助命令help…

关于时间格式yyyy-M-d或yyyy-MM-d到yyyy-MM-dd的转换

工作时遇到前端传的时间格式是"2023-12-3 17:41:52"&#xff0c;和"2023-1-1 17:41:52"但是我想要的是"2023-12-03 17:41:52"和"2023-01-01 17:41:52"。下面给大家分享几个解决方法 方法一&#xff1a; 找前端&#xff01;让他改&…

CSS属性的计算过程和层叠规则总结

✨ 专栏介绍 HTML/CSS专栏合集是一个涵盖HTML和CSS两个方面的栏目。HTML是一种标记语言&#xff0c;用于创建网页的结构和内容&#xff0c;而CSS是一种样式表语言&#xff0c;用于控制网页的外观和布局。 在HTML/CSS专栏合集中&#xff0c;我们将深入探讨HTML和CSS的基础知识…

汽车架构解析:python cantools库快速解析arxml

文章目录 前言一、安装cantools二、官方说明文档三、cantools方法1、解析message的属性2、解析pdu中的signals3、根据message查找signals4、报文组成bytes 总结 前言 曾经有拿cantools来解析过dbc&#xff0c;用得比较浅&#xff0c;不知道可以用来解析arxml。最近有个需求需要…

【纯java代码实现字符串运算符或公式计算,支持函数,不借助第三方依赖、工具】

纯java代码实现字符串运算符或公式计算&#xff0c;支持函数&#xff0c;不借助第三方依赖和工具 效果图代码 效果图 代码 import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import…

在 Oracle 数据库表中加载多个数据文件

在本文中&#xff0c;我将展示 SQL 加载器 Unix 脚本实用程序的强大功能&#xff0c;其中 SQL 加载器可以使用自动 shell 脚本加载多个数据文件。这在处理大量数据以及需要将数据从一个系统移动到另一个系统时非常有用。 它适合涉及大量历史数据的迁移项目。那么就不可能为每…

Elasticsearch:带有自查询检索器的聊天机器人示例

本工作簿演示了 Elasticsearch 的自查询检索器 (self-query retriever) 将问题转换为结构化查询并将结构化查询应用于 Elasticsearch 索引的示例。 在开始之前&#xff0c;我们首先使用 langchain 将文档分割成块&#xff0c;然后使用 ElasticsearchStore.from_documents 创建…

企业微信开发:自建应用:接收消息(企业内部服务器)/回调配置

概述 在企业微信的自建应用中&#xff0c;用户触发了某些行为&#xff08;发送消息、进行菜单操作或者外部联系人变更等&#xff09;&#xff0c;要发送相关信息给企业内部服务器。 备注&#xff1a;接收消息 和 回调&#xff0c;在本文中指代相同的行为&#xff0c;即企业微信…

Jenkins部署项目

一.安装jenkins 1.1进入jenkins官网下载jenkins war包&#xff0c;上传到服务器/usr/local目录。 1.2执行启动jenkins命令&#xff0c;&#xff08;注意jenkins版本需要的jdk版本&#xff09; /usr/local/java11/bin/java -Djava.awt.headlesstrue -jar /usr/local/jenkins.wa…

使用sdf文件+urdf文件模拟机器人示例(不用把urdf转sdf)

gazebo版本&#xff1a;harmonic&#xff1b; <launch> <group> <let name"robot_description" value"$(command xacro $(find-pkg-share gazebo_pkg)/urdf/total.xacro)"/> <node pkg"rviz2" exec"rviz2" name…

[讲座] - 闲聊工业设计

1&#xff0c;工业设计相关的学科分类 2&#xff0c;工业设计的职业发展路线 3&#xff0c;工业设计师的成名人物 4&#xff0c;设计了可口可乐的Loewy 可口可乐的瓶子&#xff0c;无论白天晚上还是瓶子被打碎&#xff0c;都能认出这个是可口可乐的瓶子。 草图参照了可可豆&am…

深度生成模型之GAN优化目标设计与改进 ->(个人学习记录笔记)

文章目录 深度生成模型之GAN优化目标设计与改进原始GAN优化目标的问题1. JS散度度量问题2. 梯度问题 优化目标的设计与改进1. 最小二乘损失GAN2. Energy-based GAN(EBGAN)3. Wasserstein GAN4. WGAN-GP5. Boundary Equilibrium GAN(BEGAN)6. Loss Sensitive GAN7. Relativeisti…

Cuk、Zeta和Sepic开关电源拓扑结构

Cuk、Zeta和Sepic变换器,三种拓扑结构大致类似。不同点在于电感和二极管&#xff0c;MOS管的位置关系的变化。 Cuk电源是一种非隔离的直流电源转换器&#xff0c;其基本结构包括输入滤波电容、开关管、输入电感、输出电感和输出电容等元件。Cuk电路可以看作是Boost和Buck电路的…

基于双闭环PI和SVPWM的PMSM控制器simulink建模与仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 4.1 双闭环PI控制器设计 4.2 SVPWM技术 4.3 控制系统实现 5.完整工程文件 1.课题概述 基于双闭环PI和SVPWM的PMSM控制器simulink建模与仿真。系统包括逆变桥、PMSM、park变换、clark变换、SVPWM、PI控…

解决电脑访问共享文件问题:“无法访问。你可能没有权限使用网络资源。请与这台服务器的......”

文章目录 1. 问题2. 解决方法 1. 问题 2. 解决方法 Win R 键入 gpedit.msc在弹出的窗口,展开左侧目录树至安全选项,如图。( 计算机配置-Windows设置:安全设置-本地策略-安全选项)