0
点赞
收藏
分享

微信扫一扫

分析ERP审单失败,提示:库存不足的原因及应对方案

婉殇成长笔记 2022-04-08 阅读 85

第一步:创建测试表 test,如下:

CREATE TABLE `test` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `now` datetime DEFAULT NULL COMMENT '时间',
  `year_month` binary(7) DEFAULT '\0\0\0\0\0\0\0',
  `stock` mediumint(11) unsigned NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8

模拟前提条件:
MySQL版本:5.7.26
事务级别:REPEATABLE-READ

第二步:模拟用户A制单、审核
START TRANSACTION;
select `stock`,`now` from test where id = 1 lock in share mode;
UPDATE test SET `stock` = `stock`-50,`now`=NOW() where id = 1;
COMMIT;

第三步:模拟用户B制单、审核
START TRANSACTION;
SELECT `stock`,`now` from test where id = 1 lock in share mode;
UPDATE test SET `stock`=`stock` - 60,`now`=NOW() WHERE id = 1;
COMMIT;

审单失败的原因分析
1.以测试的MySQL版本为例,事务的默认超时为:120秒,实际测试过程种发现,若采用默认的120秒超时机制,用户B的事务在用户A的锁超时后,会得以执行成功,通常用户B的事务被阻塞90秒左右,此时用户A的锁已经过期解除,因此用户B的事务可以正常执行,也就是说:用户A先执行扣减库存-50,但是因为某种原因没有commit,此时用户B也执行扣减库存,因为此时处于加锁状态,用户B的事务扣减库存会被阻塞,这个阻塞大概会持续90秒左右(这个阻塞时长依据实际情况会略有不同),用户A的锁过期被解除,这个时候用户B的事务得以正常执行成功并commit,此时实际库存是:stock - 60,即:100 - 60 = 40

###用户A经过长时间的搁置,已经制单,但是没有及时审核单据,过了很久,比如:迟疑超过了事务wait_timeout的半天,更甚者,第二天才来审核这个单据
2.用户A点击审单操作,这张单据是在用户B制单之前产生的,用户A要审核的单据内容是:stock - 50,即:100 - 50 = 50,然而实际情况是:用户B已经扣减库存-60,当前实际库存stock = 40,在执行用户A的第二步审核单据时,系统取得实际stock = 40,40 - 50 = -10,执行 update 失败,接着界面会提示库存不足


应对方案:
1.设置合理的事务超时:SET innodb_lock_wait_timeout=30; -- 默认的是 31536000秒
建议设置在 30 - 60 之间比较合理,假设超时为:30秒,那么用户B扣减库存时阻塞30秒,此时用户A加锁还在有效期内,用户B
2.提示信息优化:不要简单的提示 库存不足,这样用户会产生疑惑,以用户A为例:当他看到提示库存不足,他会想:这张单制单内容显示:库存100,扣减库存50,库存结余50,库存是足够扣减的,为什么会提示库存不足?
建议优化措施:库存不足时要提示出库存不足的原因,比如:库存不足,当前库存:40,待扣减50,最好还可以带出关联单据的查询,可以很直观的看出问题出在了哪里

举报

相关推荐

0 条评论