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

洛阳做网站公司电话wordpress影视模板

洛阳做网站公司电话,wordpress影视模板,增城市网站建设,wordpress换标题目录 1.1 从减库存聊起1.2 环境准备1.3 简单实现减库存1.4 演示超卖现象1.5 jvm锁1.6 三种情况导致Jvm本地锁失效1、多例模式下#xff0c;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、一个sql1.7.2、悲观锁1.7.3、乐观锁1.7.4、mysql锁总结 1.8 redis乐观锁1.8.1 引入redis1.8.2 redis乐观锁原理1.8.3 redis乐观锁解决超卖问题1.8.4 redis乐观锁的缺点 1.1 从减库存聊起 多线程并发安全问题最典型的代表就是超卖现象 库存在并发量较大情况下很容易发生超卖现象一旦发生超卖现象就会出现多成交了订单而发不了货的情况。 场景商品S库存余量为5时用户A和B同时来购买一个商品此时查询库存数都为5库存充足则开始减库存 用户Aupdate db_stock set stock stock - 1 where id 1 用户Bupdate 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) ) ENGINEInnoDB AUTO_INCREMENT1 DEFAULT CHARSETutf8;表中数据如下 创建分布式锁demo工程 目录结构 pom.xml dependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactIdversion5.1.46/version/dependencydependencygroupIdcom.baomidou/groupIdartifactIdmybatis-plus-boot-starter/artifactIdversion3.4.3.4/version/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependency/dependenciesapplication.yml配置文件 server.port10010 spring.datasource.driver-class-namecom.mysql.jdbc.Driver spring.datasource.urljdbc:mysql://192.168.239.11:3306/atguigu_distributed_lock spring.datasource.usernameroot spring.datasource.passwordhouchenDistributedLockApplication启动类 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 BaseMapperStock { }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 BaseMapperStock {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 BaseMapperStock {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 UpdateWrapperStock().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 SessionCallbackObject() {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://www.yingshimen.cn/news/56588/

相关文章:

  • 建网站不花钱免费谷歌海外广告投放
  • 上海市区网站设计制作公司山西建筑劳务网站
  • 手机网站开发免费视频教程wordpress搜索功能
  • 北师大网页制作与网站建设kali搭建wordpress
  • 网站绝对布局邵阳seo快速排名
  • 网站维护界面设计ppt背景图片
  • 网站seo优化培训傻瓜式做网站哪个软件好
  • 湖州网站建设方案网站添加支付宝
  • 做ui的网站泰州网页设计需要多少钱
  • 软文发布网站备案号被取消 没有重新备案网站会被关闭吗
  • 做网站需要提供的资料网页素材免费下载
  • 企业网站推广的模式用dw制作个人网页
  • 贵州省住房城乡建设厅网站wordpress怎么调用默认的分页代码
  • 北京市朝阳区网站开发公司申请网站建设费
  • 即墨区建设局网站wordpress 模拟post
  • 网站建设 优势手机网站建设哪家强
  • 嘉兴手机建站模板网站备案是什么
  • 好网站的特点旅游类网站模板免费下载
  • gta5此网站正在建设合肥企业网站营销电话
  • 网站开发的技术栈搜索引擎关键词竞价排名
  • 网站建设推广襄樊优化什么建立生育支持
  • 搜索引擎推广方案案例优化的含义是什么
  • 网站开发系统源代码网络营销推广方法包括哪些
  • 电商网站开发模块解聘 人力资源网站上怎么做
  • 网站推广做哪个比较好ip开源网站FPGA可以做点什么
  • 网站建设江门惠安网站建设公司
  • wordpress多站点分别部署个人网站定制
  • 网站开发中用到的英文单词乡村旅游电子商务网站建设
  • 没公司怎么做网站自己做网站的优势
  • 枣阳市建设局网站郑州服务设计公司网站