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

罗湖网站建设优化公众号如何推广引流

罗湖网站建设优化,公众号如何推广引流,上海网站建设做物流一,做房地产策划需要关注的网站目录 1.1 从减库存聊起1.2 环境准备1.3 简单实现减库存1.4 演示超卖现象1.5 jvm锁1.6 三种情况导致Jvm本地锁失效1、多例模式下,Jvm本地锁失效2、Spring的事务导致Jvm本地锁失效3、集群部署导致Jvm本地锁失效 1.7 mysql锁演示1.7.1、一个sql1.7.2、悲观锁1.7.3、乐观…

目录

    • 1.1 从减库存聊起
    • 1.2 环境准备
    • 1.3 简单实现减库存
    • 1.4 演示超卖现象
    • 1.5 jvm锁
    • 1.6 三种情况导致Jvm本地锁失效
      • 1、多例模式下,Jvm本地锁失效
      • 2、Spring的事务导致Jvm本地锁失效
      • 3、集群部署导致Jvm本地锁失效
    • 1.7 mysql锁演示
      • 1.7.1、一个sql
      • 1.7.2、悲观锁
      • 1.7.3、乐观锁
      • 1.7.4、mysql锁总结
    • 1.8 redis乐观锁
      • 1.8.1 引入redis
      • 1.8.2 redis乐观锁原理
      • 1.8.3 redis乐观锁解决超卖问题
      • 1.8.4 redis乐观锁的缺点

1.1 从减库存聊起

多线程并发安全问题最典型的代表就是超卖现象
库存在并发量较大情况下很容易发生超卖现象,一旦发生超卖现象,就会出现多成交了订单而发不了货的情况。

场景:商品S库存余量为5时,用户A和B同时来购买一个商品,此时查询库存数都为5,库存充足则开始减库存
用户A:update db_stock set stock = stock - 1 where id = 1
用户B:update db_stock set stock = stock - 1 where id = 1
并发情况下,更新后的结果可能是4,而实际的最终库存量应该是3才对 !!

1.2 环境准备

建表语句:

CREATE TABLE `db_stock` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`product_code` varchar(255) DEFAULT NULL COMMENT '商品编号',`stock_code` varchar(255) DEFAULT NULL COMMENT '仓库编号',`count` int(11) DEFAULT NULL COMMENT '库存量',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

表中数据如下:
在这里插入图片描述

创建分布式锁demo工程:

目录结构
在这里插入图片描述
pom.xml

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.46</version></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.3.4</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies>

application.yml配置文件:

server.port=10010
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://192.168.239.11:3306/atguigu_distributed_lock
spring.datasource.username=root
spring.datasource.password=houchen

DistributedLockApplication启动类:

@SpringBootApplication
@MapperScan("com.atguigu.distributed.lock.mapper")
public class DistributedLockApplication {public static void main(String[] args) {SpringApplication.run(DistributedLockApplication.class, args);}}

Stock实体类:

@Data
@TableName("db_stock")
public class Stock {@TableIdprivate Long id;private String productCode;private String stockCode;private Integer count;
}

StockMapper接口:

public interface StockMapper extends BaseMapper<Stock> {
}

1.3 简单实现减库存

在这里插入图片描述

@RestController
public class StockController {@Autowiredprivate StockService stockService;@GetMapping("stock/deduct")public String deduct(){this.stockService.deduct();return "hello stock deduct!!";}}@Service
public class StockService {@Autowiredprivate StockMapper stockMapper;public void  deduct(){// 先查询库存是否充足Stock stock = this.stockMapper.selectById(1L);// 再减库存if (stock != null && stock.getCount() > 0){stock.setCount(stock.getCount() - 1);this.stockMapper.updateById(stock);}}
}

测试:
在这里插入图片描述

查看数据库:
在这里插入图片描述

在浏览器中一个一个访问时,每访问一次,库存量减1,没有任何问题。

1.4 演示超卖现象

使用jmeter压力测试工具,高并发下压测一下,添加线程组:并发100循环50次,即5000次请求。
在这里插入图片描述
在这里插入图片描述

启动测试,查看压力测试报告:
在这里插入图片描述

  • Label 取样器别名,如果勾选Include group name ,则会添加线程组的名称作为前缀
  • # Samples 取样器运行次数
  • Average 请求(事务)的平均响应时间
  • Median 中位数
  • 90% Line 90%用户响应时间
  • 95% Line 90%用户响应时间
  • 99% Line 90%用户响应时间
  • Min 最小响应时间
  • Max 最大响应时间
  • Error 错误率
  • Throughput 吞吐率
  • Received KB/sec 每秒收到的千字节
  • Sent KB/sec 每秒收到的千字节

查看mysql数据库剩余库存数:还有4818
在这里插入图片描述

1.5 jvm锁

使用jvm锁(synchronized关键字或者ReetrantLock)试试:

 /***  使用jvm锁来解决超卖问题*/public synchronized void deduct() {// 先查询库存是否充足Stock stock = this.stockMapper.selectById(1L);// 再减库存if (stock != null && stock.getCount() > 0) {stock.setCount(stock.getCount() - 1);this.stockMapper.updateById(stock);}}

重启tomcat服务,再次使用jmeter压力测试,效果如下:
在这里插入图片描述
可以看到,加锁之后,吞吐量减少了一倍多!

查看mysql数据库:
在这里插入图片描述
并没有发生超卖现象,完美解决。

原理
添加synchronized关键字之后,同一时刻只有一个请求能够获取到锁,并减库存。此时,所有请求只会one-by-one执行下去,也就不会发生超卖现象
在这里插入图片描述

1.6 三种情况导致Jvm本地锁失效

1、多例模式下,Jvm本地锁失效

原理:StockService有多个对象,不同的对象持有不同的锁,所以还是会有多个线程进入到 临界区

演示:

@Service
@Scope(value = "prototype",proxyMode = ScopedProxyMode.TARGET_CLASS)
public class StockService {@Autowiredprivate StockMapper stockMapper;/***  使用jvm锁来解决超卖问题*/public synchronized void deduct() {// 先查询库存是否充足Stock stock = this.stockMapper.selectById(1L);// 再减库存if (stock != null && stock.getCount() > 0) {stock.setCount(stock.getCount() - 1);this.stockMapper.updateById(stock);}}
}

重启tomcat服务,再次使用jmeter压力测试,查看数据库,发现库存确实没有减到 0 ,发生超卖
在这里插入图片描述

2、Spring的事务导致Jvm本地锁失效

在加锁的地方加上 @Transactional 注解

 @Transactionalpublic synchronized void deduct() {// 先查询库存是否充足Stock stock = this.stockMapper.selectById(1L);// 再减库存if (stock != null && stock.getCount() > 0) {stock.setCount(stock.getCount() - 1);this.stockMapper.updateById(stock);}}

重启tomcat服务,再次使用jmeter压力测试,查看数据库,发现库存确实没有减到 0 ,发生超卖
在这里插入图片描述

造成超卖的原因:
Spring事务默认的隔离级别是可重复读
在这里插入图片描述

解决办法
扩大锁的范围,将开启事务,提交事务也包括在锁的代码块中

 @GetMapping("stock/deduct")public String deduct(){synchronized (this) {this.stockService.deduct();}return "hello stock deduct!!";}

3、集群部署导致Jvm本地锁失效

使用jvm锁在单工程单服务情况下确实没有问题,但是在集群情况下会怎样?

接下启动多个服务并使用nginx负载均衡

1)启动两个服务(端口号分别10010 10086),如下:
在这里插入图片描述

2)配置nginx 负载均衡

#user  nobody;
worker_processes  1;#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;#pid        logs/nginx.pid;events {worker_connections  1024;
}http {include       mime.types;default_type  application/octet-stream;sendfile        on;upstream distributed {server localhost:10010;server localhost:10086;}server {listen       80;server_name  localhost;location / {proxy_pass http://distributed;}}
}

3)在post中测试:http://localhost/stock/deduct (其中80是nginx的监听端口)
在这里插入图片描述
请求正常,说明nginx负载均衡起作用了

4) Jmeter压力测试
注意

  • 先把数据库库存量还原到5000
  • 重新配置访问路径 http://localhost:80/stock/deduct
    在这里插入图片描述
    两台机器时,吞吐量明显大于单个机器

查看数据库,库存不为0,表示多服务时,Jvm锁失效
在这里插入图片描述

5) 原因
每个服务都有自己的本地锁,所以无法锁住临界区,导致多线程的安全问题

1.7 mysql锁演示

除了使用jvm锁之外,还可以使用mysql自带的锁:悲观锁 或者 乐观锁

1.7.1、一个sql

update db_stock set count = count - 1 where product_code = '1001' and count >= #{count}
public void deduct() {this.stockMapper.updateStock("1001", 1);}public interface StockMapper extends BaseMapper<Stock> {@Update("update db_stock set count = count - #{count} where product_code = #{productCode} and count >= #{count}")int updateStock(@Param("productCode") String productCode, @Param("count") Integer count);
}

这种方式可以解决上述Jvm锁失效的三个问题

缺点:
1、确定好锁范围
当使用的是表锁时,会导致系统的吞吐量直线下降

​ 什么情况下会使用行级锁

​ 1)锁的查询或者更新条件必须是索引字段

​ 2) 查询或者更新条件必须是具体值

2、一件商品多个仓库问题无法处理

3、无法记录仓库变化前后的状态

1.7.2、悲观锁

SELECT ... FOR UPDATE                     (悲观锁)

代码实现

改造StockService: 添加事务注解,去掉synchronized关键词

@Transactionalpublic void deduct() {Stock stocks = this.stockMapper.queryStockForUpdate("1001");if (stocks != null && stocks.getCount() > 0) {stocks.setCount(stocks.getCount() - 1);this.stockMapper.updateById(stocks);}}

在StockeMapper中定义selectStockForUpdate方法:

public interface StockMapper extends BaseMapper<Stock> {@Update("update db_stock set count = count - #{count} where product_code = #{productCode} and count >= #{count}")int updateStock(@Param("productCode") String productCode, @Param("count") Integer count);@Select("select * from db_stock where product_code = #{productCode} for update")Stock queryStockForUpdate(@Param("productCode") String productCode);
}

压力测试
注意:测试之前,需要把库存量改成5000。压测数据如下:比jvm锁性能高很多
在这里插入图片描述
mysql数据库存:
在这里插入图片描述

【注意】使用MySQL乐观锁时,也需要注意锁的粒度,尽量使用行级锁,否则系统吞吐量会降低

1.7.3、乐观锁

乐观锁是相对悲观锁而言,乐观锁假设认为数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则重试。

使用数据版本(Version)记录机制实现,这是乐观锁最常用的实现 方式。一般是通过为数据库表增加一个数字类型的 “version” 字段来实现。当读取数据时,将version字段的值一同读出,数据每更新一次,对此version值加一。当我们提交更新的时候,判断数据库表对应记录的当前版本信息与第一次取出来的version值进行比对,如果数据库表当前版本号与第一次取出来的version值相等,则予以更新。

给db_stock表添加version字段:
在这里插入图片描述

改造 StockService

  /***  使用MySQL乐观锁来解决库存超卖问题*/public void deduct() {// 先查询库存是否充足Stock stock = this.stockMapper.selectById(1L);// 再减库存if (stock != null && stock.getCount() > 0){// 获取版本号Long version = stock.getVersion();stock.setCount(stock.getCount() - 1);// 每次更新 版本号 + 1stock.setVersion(stock.getVersion() + 1);// 更新之前先判断是否是之前查询的那个版本,如果不是重试if (this.stockMapper.update(stock, new UpdateWrapper<Stock>().eq("id", stock.getId()).eq("version", version)) == 0) {deduct();}}}

重启后使用jmeter压力测试工具结果如下:
在这里插入图片描述
在这里插入图片描述
并发度比较低,说明乐观锁在并发量越大的情况下,性能越低(因为需要大量的重试);并发量越小,性能越高。

乐观锁存在的问题

  • 高并发情况下,性能较低
  • ABA问题
  • 读写分离的情况下,可能会导致乐观锁不可靠

1.7.4、mysql锁总结

性能:一个sql > 悲观锁 > jvm锁 > 乐观锁

  • 如果追求极致性能、业务场景简单并且不需要记录数据前后变化的情况下。

​ 优先选择:一个sql

  • 如果写并发量较低(多读),争抢不是很激烈的情况下优先选择:乐观锁

  • 如果写并发量较高,一般会经常冲突,此时选择乐观锁的话,会导致业务代码不间断的重试。

​ 优先选择:mysql悲观锁

  • 不推荐jvm本地锁。

1.8 redis乐观锁

1.8.1 引入redis

见我的博客 https://blog.csdn.net/hc1285653662/article/details/127564372 中的SpringDataRedis客户端

改造StockService

  /*** 为了提高请求响应的速度,将库存放在redis中进行操作*/public void deduct() {// 先查询库存是否充足String stockStr = redisTemplate.opsForValue().get("stock:" + "1001");Long stock = Long.parseLong(stockStr);if (stock != null && stock > 0) {redisTemplate.opsForValue().set("stock:" + "1001", String.valueOf(stock - 1));}}

演示redis库存超卖
设置redis库存为 5000
在这里插入图片描述
jmeter启动测试,可以看到并发比无锁时候的mysql库存要高
在这里插入图片描述
查询redis库存,发现剩余库存不为0,所以发生超卖现象
在这里插入图片描述

1.8.2 redis乐观锁原理

使用watch命令监视某个key,如果在监视的过程中该key被某个客户端修改后,那么自身对于key的修改将会失败
在这里插入图片描述

1.8.3 redis乐观锁解决超卖问题

改造StockService

/*** 为了提高请求响应的速度,将库存放在redis中进行操作*/public void deduct() {// 监听 stock:1001redisTemplate.execute(new SessionCallback<Object>() {@Overridepublic Object execute(RedisOperations operations) throws DataAccessException {operations.watch("stock:" + "1001");String stockStr = (String) operations.opsForValue().get("stock:" + "1001");Long stock = Long.parseLong(stockStr);if (stock != null && stock > 0) {operations.multi();operations.opsForValue().set("stock:" + "1001", String.valueOf(stock - 1));List exec = operations.exec();// 如果减库存失败,代表key别其他客户端修改了,则进行重试if (exec == null || exec.size() == 0) {try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}deduct();}return exec;}return null;}});}

查看测试结果:发现并发很低(可能因为我redis部署在阿里云上的docker里,网络开销导致并发很低),但是确实解决超卖问题
在这里插入图片描述
在这里插入图片描述

1.8.4 redis乐观锁的缺点

  • 性能问题

文章转载自:
http://musicomania.fcxt.cn
http://rnr.fcxt.cn
http://saltpetre.fcxt.cn
http://repellancy.fcxt.cn
http://noachian.fcxt.cn
http://noteworthy.fcxt.cn
http://turcoman.fcxt.cn
http://sunbreaker.fcxt.cn
http://bacilus.fcxt.cn
http://saucerman.fcxt.cn
http://semester.fcxt.cn
http://racontage.fcxt.cn
http://manikin.fcxt.cn
http://peachick.fcxt.cn
http://photoconductor.fcxt.cn
http://jonnop.fcxt.cn
http://manfully.fcxt.cn
http://pillular.fcxt.cn
http://thrapple.fcxt.cn
http://gentisate.fcxt.cn
http://sorely.fcxt.cn
http://principally.fcxt.cn
http://passage.fcxt.cn
http://psychoanalysis.fcxt.cn
http://landsturm.fcxt.cn
http://whippersnapper.fcxt.cn
http://rightie.fcxt.cn
http://unionize.fcxt.cn
http://sallenders.fcxt.cn
http://tenno.fcxt.cn
http://bandspreading.fcxt.cn
http://einkorn.fcxt.cn
http://shweli.fcxt.cn
http://resonator.fcxt.cn
http://cymagraph.fcxt.cn
http://wolverhampton.fcxt.cn
http://acrimony.fcxt.cn
http://almsgiver.fcxt.cn
http://misbeseem.fcxt.cn
http://ceremoniously.fcxt.cn
http://lagoon.fcxt.cn
http://dilatoriness.fcxt.cn
http://knackwurst.fcxt.cn
http://portcrayon.fcxt.cn
http://backbreaker.fcxt.cn
http://tabet.fcxt.cn
http://ordinal.fcxt.cn
http://leavisian.fcxt.cn
http://trinitroglycerin.fcxt.cn
http://diffrangible.fcxt.cn
http://auramine.fcxt.cn
http://nub.fcxt.cn
http://boschbok.fcxt.cn
http://unnilhexium.fcxt.cn
http://zoophoric.fcxt.cn
http://romanist.fcxt.cn
http://soliflucted.fcxt.cn
http://bacteriolysis.fcxt.cn
http://riot.fcxt.cn
http://pard.fcxt.cn
http://juridical.fcxt.cn
http://spoliaopima.fcxt.cn
http://freedman.fcxt.cn
http://unzealous.fcxt.cn
http://precancel.fcxt.cn
http://pouch.fcxt.cn
http://icarian.fcxt.cn
http://pessary.fcxt.cn
http://dcc.fcxt.cn
http://irkutsk.fcxt.cn
http://napoleonic.fcxt.cn
http://lhasa.fcxt.cn
http://nauplial.fcxt.cn
http://blather.fcxt.cn
http://quindecagon.fcxt.cn
http://avenging.fcxt.cn
http://ultracentrifugal.fcxt.cn
http://abranchiate.fcxt.cn
http://vindicative.fcxt.cn
http://unflinching.fcxt.cn
http://inventory.fcxt.cn
http://syphiloid.fcxt.cn
http://peart.fcxt.cn
http://pineal.fcxt.cn
http://lattin.fcxt.cn
http://ambisyllabic.fcxt.cn
http://diazoamino.fcxt.cn
http://prepositive.fcxt.cn
http://rcvs.fcxt.cn
http://elements.fcxt.cn
http://vicky.fcxt.cn
http://lamplighter.fcxt.cn
http://caracole.fcxt.cn
http://axletree.fcxt.cn
http://phocomelia.fcxt.cn
http://redintegrate.fcxt.cn
http://allopath.fcxt.cn
http://omar.fcxt.cn
http://divan.fcxt.cn
http://belize.fcxt.cn
http://www.hrbkazy.com/news/63104.html

相关文章:

  • 东营做网站公司bt磁力
  • 上海疫情为何不追责windows优化大师值得买吗
  • 制作网站的登录界面怎么做夜狼seo
  • 帝国软件怎么做网站站长工具在线
  • 企业建一个网站百度法务部联系方式
  • 网站建设公司muyunke百度竞价推广方法
  • felis wordpress长沙seo就选智优营家
  • 黄骅做网站_黄骅昊信科技|黄骅网站|黄骅网站开发|黄骅微信|黄骅外链网站是什么
  • 烟台做网站推广的公司哪家好常见的营销方式有哪些
  • 建设一个网站需要哪些费用吗免费学生网页制作成品代码
  • 免费做动态图片的网站武汉网站开发公司
  • 自己的网站怎么做app搜索引擎有哪些网站
  • WordPress播放背景音乐盐城seo网站优化软件
  • 怎么知道哪家公司网站做的好重庆网站seo技术
  • dede网站文章同步哪里有正规的电商培训班
  • 网站建设 贸易青岛做网络推广的公司有哪些
  • 手机移动端网站做多大百度旗下产品
  • 做网站一般收取多少钱手机端网站排名
  • 织梦html网站地图网络营销方式与工具有哪些
  • 沧州网站建设申梦百度推广官方网站登录入口
  • 模板网站会员百度收录查询api
  • 珠海房地产网站建设百度一下百度百科
  • dw做的网站与浏览器不匹配网站seo推广多少钱
  • 合肥智能建站模板桂林seo排名
  • 免费个人网站源码最佳磁力吧ciliba
  • 南通seo网站诊断线上营销推广
  • 淘宝联盟个人网站怎么做所有关键词
  • b2c网站的模式百度有免费推广广告
  • 如何制作宣传小视频商丘搜索引擎优化
  • brackets做的网站好的推广方式