一个商城项目,用户下单时需要更新商品库存,在商品类增加了version字段,增加乐观锁,保证库存数据的线程安全,但是在多个用户同时下单更新库存时可能会导致库存更新失败,因此需要增加乐观锁失败重试机制

一、相关代码

(1)商品实体类

@Data
@ApiModel(value = "Goods对象", description = "Goods对象")
public class Goods {@ApiModelProperty(value = "商品名称")private String name;@ApiModelProperty(value = "商品标题图")private String tittleImg;@ApiModelProperty(value = "商品数量")private Integer quantity;@ApiModelProperty(value = "展示价格")private BigDecimal price;@ApiModelProperty(value = "商品详情")private String details;@ApiModelProperty(value = "商品分类")private String category;@ApiModelProperty(value = "版本")@Versionprivate Integer version;
}

(2)失败重试注解类

import java.lang.annotation.*;@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FailRetry {//重试次数,这里默认15int value() default 15;
}

(3)重试切面类

import XXXX.exception.TryAgainException;  //类的路径自行修改
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;@Aspect
@Configuration
@Slf4j
public class TryAgainAspect {/*** 定义切点*/@Pointcut("@annotation(com.ht.store.annotation.FailRetry)")private void failRetryPointCut() {}@Around("failRetryPointCut() && @annotation(failRetry)")@Transactional(rollbackFor = Exception.class)public Object retry(ProceedingJoinPoint joinPoint, FailRetry failRetry) throws Throwable {int count = 0;do {count++;try {log.info("重试次数:{}", count);return joinPoint.proceed();} catch (TryAgainException e) {if(count >= failRetry.value()){TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();throw new TryAgainException("重试失败");}}} while (true);}
}

(3)更新失败异常类

public class TryAgainException extends RuntimeException {public TryAgainException(String  e) {super(e);}
}

(4)库存更新方法,注意方法上加上注解

@Override
@FailRetry
@Transactional(rollbackFor = TryAgainException.class)
public boolean updateGoodsQuantity(Long id,Integer number) {Goods goods = this.getById(id);goods.setQuantity(goods.getQuantity() - number);if (this.updateById(goods)){return true;}else{throw  new TryAgainException("更新异常,版本号不一致");}
}

二、执行测试

数据库商品目前库存976,version是23

调用接口更新库存 -1

更新成功了,查看数据库

修改代码,模拟一次更新失败

@Override
@FailRetry
@Transactional(rollbackFor = TryAgainException.class)
public boolean updateGoodsQuantity(Long id,Integer number) {Goods goods = this.getById(id);goods.setQuantity(goods.getQuantity() - number);goods.setVersion(20);  //此处修改为老版本,肯定更新失败if (this.updateById(goods)){return true;}else{throw  new TryAgainException("更新异常,版本号不一致");}
}

更新时version是20,而数据库的version是24,会判定为老版本,表示已经被更新过,会更新失败,触发异常,然后去执行重试机制

抛出TryAgainException异常,数据回滚,由于方法有@FailRetry注解,进入注解绑定的切面类

注解类FailRetry里面默认15次,最多重试15次,结束重试。

一般情况下,每次更新前读取最新的,然后减掉库存进行更新,失败的次数不会太多,可以满足日常使用。

Springboot:商品库存并发更新,乐观锁失败重试机制相关推荐

  1. mysql乐观锁重试_乐观锁失败重试

    1.乐观锁失败后会报:ObjectOptimisticLockFailureException 2.处理方案:捕获到对应乐观锁失败异常后进行重试,代码参考如下 在写入数据库的时候需要有锁,比如同时写入 ...

  2. Elasticsearch 并发修改乐观锁

    2019独角兽企业重金招聘Python工程师标准>>> Elasticsearch 并发修改乐观锁 博客分类: 搜索引擎,爬虫 来自: http://blog.csdn.net//j ...

  3. Java并发问题--乐观锁与悲观锁以及乐观锁的一种实现方式-CAS

    Java并发问题–乐观锁与悲观锁以及乐观锁的一种实现方式-CAS </h1><div class="clear"></div><div c ...

  4. invalid signature 错误原因验签失败_Nginx 失败重试机制

    可直接点击上方蓝字 (网易游戏运维平台) 关注我们,获一手游戏运维方案 src 网易游戏 SRE,喜欢钻研与分享. 背景 Nginx 作为目前应用较广的反向代理服务,原生提供了一套失败重试机制,来保证 ...

  5. 自动化测试实例分享——《用例失败重试机制》

    1. 背景说明 在开展自动化测试工作时,经常会由于一些外在原因(如网络中断.返回超时)导致自动化测试用例运行失败,而这些失败并不是用例本身验证或被测程序存在Bug而引起的,更可气的是这些失败场景有可能 ...

  6. mysql乐观锁重试_乐观锁加重试,并发更新数据库一条记录导致:Lock wait timeout exceeded...

    背景: mysql数据库,用户余额表有一个version(版本号)字段,作为乐观锁. 更新方法有事务控制: @Transactional(rollbackFor = Exception.class) ...

  7. Springboot秒杀系统(乐观锁+RateLimiter令牌+Redis缓存)

    本文主要是利用springboot,实现一个单机版秒杀demo,通过单机版实现,可以对基本并发秒杀的知识有一定的了解. 首先先提供秒杀业务实现类: /*** spring 注解加在实现类*/ @Ser ...

  8. jpa mysql乐观锁_【快学springboot】8.JPA乐观锁OptimisticLocking

    介绍 当涉及到企业应用程序时,正确地管理对数据库的并发访问是至关重要的.为此,我们可以使用Java Persistence API提供的乐观锁定机制.它导致在同一时间对同一数据进行多次更新不会相互干扰 ...

  9. springboot 使用mybatis-plus 配置乐观锁。

    -----------------------------官方文档已更新,详细配置请访问:mybatis plus乐观锁插件 进行查看--------------------------------- ...

最新文章

  1. 4岁的儿子还不会写红黑树,我该怎么办?
  2. Kali Linux WPScan更新到2.9.3
  3. CentOS 6.5 64位 安装Nginx, MySQL, PHP
  4. Android新手入门2016(15)--Gallery画廊
  5. 宏观经济之国家经济与建设
  6. nodejs连接redis,redis服务器的地址格式应该怎么写
  7. ROS环境下跑orb-slam2 单目相机
  8. 运行tomcat报Exception in thread ContainerBackgroundProcessor[StandardEngine[Catalina]]
  9. Android实例-拍摄和分享照片、分享文本(XE8+小米2)
  10. 高效、稳定开发功能的一些心得
  11. Django - 两周从入门到熟练工
  12. 编译OpenJDK8:specified bound depends on the length of the source argument
  13. 【转】Ubuntu 16.04安装配置TensorFlow GPU版本
  14. 计算机图形学——计算机图形系统及硬件基础
  15. 安吉丽娜-朱莉曝光罕见少女照(图)
  16. js调用Python函数
  17. [宋史学习] 宋初对党项的征讨与妥协
  18. 递归最小二乘法、增广最小二乘法、带遗忘因子的递归增广最小二乘法
  19. 面试题,互联网产品的盈利模式有哪些?
  20. 华为刀片服务器 安装文档,刀片服务器主机

热门文章

  1. 强强联合 数睿数据与霍尼韦尔Tridium达成战略合作
  2. 世界各国 省市县 省份 城市 三级数据库表 mysql
  3. uni-app实现PDF预览功能(避坑看这)
  4. 阻止浏览器默认行为事件
  5. c3p0plugin mysql,四十八、5.12 多数据源支持
  6. 使用Redis如何设置永久密码
  7. IOS7 适配以及向下兼容问题
  8. 安装织梦的时候出现dir怎么办?亲测有效解决方案
  9. 基于GeoServer的电子地图系统说明
  10. ubuntu20.04设置为中文