当前位置: 首页 > news >正文

苏州做网站公司 速选苏州聚尚网络企业型商务网站制作

苏州做网站公司 速选苏州聚尚网络,企业型商务网站制作,企业网站备案信息查询,wordpress 插件检测前言 在上一节内容中我们介绍了如何使用mysql数据库的传统锁#xff08;行锁、乐观锁、悲观锁#xff09;来解决并发访问导致的“超卖问题”。虽然mysql的传统锁能够很好的解决并发访问的问题#xff0c;但是从性能上来讲#xff0c;mysql的表现似乎并不那么优秀#xff…前言 在上一节内容中我们介绍了如何使用mysql数据库的传统锁行锁、乐观锁、悲观锁来解决并发访问导致的“超卖问题”。虽然mysql的传统锁能够很好的解决并发访问的问题但是从性能上来讲mysql的表现似乎并不那么优秀而且会受制于单点故障。本节内容我们介绍一种性能更加优良的解决方案使用内存数据库redis实现分布式锁从而控制并发访问导致的“超卖”问题。关于redis环境的搭建这里不做介绍可查看作者往期博客内容。 正文 在项目中添加redis的依赖和配置信息 - pom依赖配置 !-- 数据库连接池工具包-- dependencygroupIdorg.apache.commons/groupIdartifactIdcommons-pool2/artifactId /dependency!--redis启动器-- dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId /dependency- application.yml配置 spring:application:name: ht-atp-platdatasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://192.168.110.88:3306/ht-atp?characterEncodingutf-8serverTimezoneGMT%2B8useAffectedRowstruenullCatalogMeansCurrenttrueusername: rootpassword: rootprofiles:active: dev# redis配置redis:host: 192.168.110.88lettuce:pool:# 连接池最大连接数(使用负值表示没有限制) 默认为8max-active: 8# 连接池中的最小空闲连接 默认为 0min-idle: 1# 连接池最大阻塞等待时间(使用负值表示没有限制) 默认为-1max-wait: 1000# 连接池中的最大空闲连接 默认为8max-idle: 8 - redis序列化配置 package com.ht.atp.plat.config;import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator; 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 {/*** param factory* return*/Beanpublic RedisTemplateString, Object redisTemplate(RedisConnectionFactory factory) {// 缓存序列化配置避免存储乱码RedisTemplateString, Object template new RedisTemplate();template.setConnectionFactory(factory);Jackson2JsonRedisSerializer jackson2JsonRedisSerializer new Jackson2JsonRedisSerializer(Object.class);ObjectMapper objectMapper new ObjectMapper();objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);jackson2JsonRedisSerializer.setObjectMapper(objectMapper);StringRedisSerializer stringRedisSerializer new StringRedisSerializer();// key采用String的序列化方式template.setKeySerializer(stringRedisSerializer);// hash的key也采用String的序列化方式template.setHashKeySerializer(stringRedisSerializer);// value序列化方式采用jacksontemplate.setValueSerializer(jackson2JsonRedisSerializer);// hash的value序列化方式采用jacksontemplate.setHashValueSerializer(jackson2JsonRedisSerializer);template.afterPropertiesSet();return template;} } 在redis中增加商品P0001的库存数量为10000 使用redis不加锁的业务测试 - 业务测试代码 /*** 使用redis不加锁*/Overridepublic void checkAndReduceStock() {// 1. 查询库存数量String stockQuantity redisTemplate.opsForValue().get(P0001).toString();// 2. 判断库存是否充足if (stockQuantity ! null stockQuantity.length() ! 0) {Integer quantity Integer.valueOf(stockQuantity);if (quantity 0) {// 3.扣减库存redisTemplate.opsForValue().set(P0001, String.valueOf(--quantity));}}} - 使用jmeter压测查看测试结果库存并没有减少为0说明存在“超卖”问题 使用redis的setnx指令加锁开启三个相同服务使用jmeter压测 - redis加锁测试代码 /*** 使用redis加锁* */Overridepublic void checkAndReduceStock() {// 1.使用setnx加锁Boolean lock redisTemplate.opsForValue().setIfAbsent(lock-stock, 0000);// 2.重试递归调用,如果获取不到锁if (!lock) {try {//暂停50msThread.sleep(50);this.checkAndReduceStock();} catch (InterruptedException e) {e.printStackTrace();}} else {try {// 3. 查询库存数量String stockQuantity (String) redisTemplate.opsForValue().get(P0001);// 4. 判断库存是否充足if (stockQuantity ! null stockQuantity.length() ! 0) {Integer quantity Integer.valueOf(stockQuantity);if (quantity 0) {// 5.扣减库存redisTemplate.opsForValue().set(P0001, String.valueOf(--quantity));}} else {System.out.println(该库存不存在);}} finally {// 5.解锁redisTemplate.delete(lock-stock);}}} - 开启服务7000、7001、7002  - jmeter压测结果平均访问时间364ms接口吞吐量为每秒249 - redis数据库库存结果为0并发“超卖”问题解决 以上普通加锁方式存在死锁问题及死锁问题的解决方案 - 死锁产生的原因在上述redis加锁的正常情况下是可以解决并发访问的问题但是也存在死锁的问题例如7000的服务获取到锁之后由于服务异常导致锁没有释放那么7001和7002服务将永远不可能获取到锁。 - 解决方案给锁设置过期时间自动释放锁 ①使用expire设置过期时间缺乏原子性如果在setnx和expire之间出现异常锁也无法释放 ②使用setex指令设置过期时间set key value ex 3 nx保证原子性操作既达到setnx的效果又设置了过期时间 - 代码实现 public void checkAndReduceStock() {// 1.使用setex加锁,保证加锁的原子性以及锁可以自动释放Boolean lock redisTemplate.opsForValue().setIfAbsent(lock-stock, 0000,3, TimeUnit.SECONDS);// 2.重试递归调用,如果获取不到锁if (!lock) {try {//暂停50msThread.sleep(50);this.checkAndReduceStock();} catch (InterruptedException e) {e.printStackTrace();}} else {try {// 3. 查询库存数量String stockQuantity (String) redisTemplate.opsForValue().get(P0001);// 4. 判断库存是否充足if (stockQuantity ! null stockQuantity.length() ! 0) {Integer quantity Integer.valueOf(stockQuantity);if (quantity 0) {// 5.扣减库存redisTemplate.opsForValue().set(P0001, String.valueOf(--quantity));}} else {System.out.println(该库存不存在);}} finally {// 5.解锁redisTemplate.delete(lock-stock);}}} - 测试结果库存扣减为0锁也释放 防止误删在以上普通加锁的方式下存在锁被误删除的情况 - 锁误删除的原因在上面的加锁场景中会出现以下的情况A请求方法获取到锁之后在业务还没有执行完成锁就被自动释放这个时候B请求方法也会获取到锁在B业务还未执行完成之前A执行完成并执行手动删除锁操作这个时候会把B业务的锁释放掉导致B刚刚获取到锁就被释放从而产生后续的并发访问问题。 - 模拟锁误删除产生的并发问题 - 库存扣减结果没有扣减为0产生并发问题 - 解决方案每个请求使用全局唯一UUID为value值删除锁之前先判断value值是否相同相同再删除锁 public void checkAndReduceStock() {// 1.使用setex加锁,保证加锁的原子性以及锁可以自动释放String uuid UUID.randomUUID().toString();Boolean lock redisTemplate.opsForValue().setIfAbsent(lock-stock, uuid, 1, TimeUnit.SECONDS);// 2.重试递归调用,如果获取不到锁if (!lock) {try {//暂停50msThread.sleep(10);this.checkAndReduceStock();} catch (InterruptedException e) {e.printStackTrace();}} else {try {// 3. 查询库存数量String stockQuantity (String) redisTemplate.opsForValue().get(P0001);// 4. 判断库存是否充足if (stockQuantity ! null stockQuantity.length() ! 0) {Integer quantity Integer.valueOf(stockQuantity);if (quantity 0) {// 5.扣减库存redisTemplate.opsForValue().set(P0001, String.valueOf(--quantity));}} else {System.out.println(该库存不存在);}} finally {// 5.先判断是否是自己的锁然后再解锁String redisUuid (String) redisTemplate.opsForValue().get(lock-stock);if (StringUtils.equals(uuid, redisUuid)) {redisTemplate.delete(lock-stock);}}}} - 存在的问题由于判断锁和解锁的操作不具有原子性仍然会存在误删除的操作如A请求在完成判断之后准备删除锁的时候此时A的锁自动释放B请求获取到锁这个时候A请求会手动将B请求的锁删除掉依然存在并发访问的问题。该概率很小。 使用lua脚本解决锁手动释放删除的操作是原子性操作 - lua代码解决误删操作 public void checkAndReduceStock() {// 1.使用setex加锁,保证加锁的原子性以及锁可以自动释放String uuid UUID.randomUUID().toString();Boolean lock redisTemplate.opsForValue().setIfAbsent(lock-stock, uuid, 1, TimeUnit.SECONDS);// 2.重试递归调用,如果获取不到锁if (!lock) {try {//暂停50msThread.sleep(10);this.checkAndReduceStock();} catch (InterruptedException e) {e.printStackTrace();}} else {try {// 3. 查询库存数量String stockQuantity (String) redisTemplate.opsForValue().get(P0001);// 4. 判断库存是否充足if (stockQuantity ! null stockQuantity.length() ! 0) {Integer quantity Integer.valueOf(stockQuantity);if (quantity 0) {// 5.扣减库存redisTemplate.opsForValue().set(P0001, String.valueOf(--quantity));}} else {System.out.println(该库存不存在);}} finally {// 5.先判断是否是自己的锁然后再解锁String script if redis.call(get, KEYS[1]) ARGV[1] then return redis.call(del, KEYS[1]) else return 0 end;redisTemplate.execute(new DefaultRedisScript(script, Boolean.class), Arrays.asList(lock-stock), uuid);}}} 结语 关于使用redis分布式锁解决“超卖”问题的内容到这里就结束了我们下期见。。。。。。
http://www.pierceye.com/news/871070/

相关文章:

  • 建设网站龙华怎么用自己的电脑搭建网站
  • 分析网站的网站福建交科建设有限公司官方网站
  • 深圳南园网站建设网站域名怎么设置方法
  • 网站的内链是什么意思网页布局有哪几种方法
  • 网站优化公司上海山东电力建设河北分公司网站
  • 甘肃省住房和城乡建设部网站首页专门网页制作工具有
  • 网站用vps做dns做网站的叫什么职位
  • 网站开发业务流程图网站商城与网站区别吗
  • 用新浪微博做网站百度找不到 网站
  • 哪个网站做照片书最好seo投放是什么意思
  • 书店网站开发目的和意义深圳网建公司
  • 餐饮网站方案wordpress 微论坛主题
  • 上海建筑网站设计多用户商城数据库设计
  • 网站做301将重定向到新域名深圳seo优化外包公司
  • 做视频导航网站有哪些天津西青区离哪个火车站近
  • 福州网站建设技术支持公司培训课程有哪些
  • 保定网站制作域名注册商查询
  • 医院网站建设公司价格低天津建设工程信息网 塘沽一中
  • 建设机械网站案例建国外网站需要多少钱
  • 比特币简易网站开发电商网站大全
  • 秀屿区建设局网站巨量广告投放平台
  • 合肥网站设计哪家公司好北京国贸网站建设公司
  • 帮人做网站怎么收费制作链接的app的软件有哪些
  • 商贸行业网站建设公司yoast wordpress seo
  • 上小学网站建设WordPress底部添加运行时间
  • 学校网站信息化建设工作心得网络营销现状分析
  • 藁城专业网站建设班级同学录网站建设
  • 北京手机网站开发公司wordpress用户列表
  • 上海 企业网站制成都营销型网站建设熊掌号
  • 无锡网站优化哪家好北京注册公司地址可以是住宅吗