当前位置: 首页 > 科技观察

基于MySQL

时间:2023-03-19 23:29:49 科技观察

后台的互联网业务幂等实现在互联网业务领域,我们经常会遇到幂等性应用于请求的问题,即多次重复请求,得到的结果与一次请求一致。以某互联网电商取消的订单为例。取消订单时,需要返还消费者消费的虚拟商品,如优惠券、红包、京豆等,通过幂等的形式保证返还给消费者的权益不多。幂等性的具体开发是如何实现的呢?本文带来基于MySQL的UNIQUEKEY的实现方案。众所周知,UNIQUEKEY是数据库中的唯一索引,数据库的记录中不允许出现重复值。我们可以利用这个在处理业务之前插入唯一索引数据(比如orderid):插入成功,说明是第一次插入,业务处理正常;如果插入失败,说明业务逻辑已经处理完毕,不处理提前返回;这样,就可以实现幂等性。1.数据库设计幂等副表设计如下:CREATETABLE`idempotent_validate`(`id`bigintNOTNULL,`create_time`timeDEFAULTNULL,`order_id`bigintDEFAULTNULL,PRIMARYKEY(`id`),UNIQUEKEY`UK_orssam7fgn4uj0lo2sn4on6vg`(`order_id`))ENGINE=InnoDBDEFAULTCHARSET=utf8mb4COLLATE=utf8mb4_0900_ai_ci;其中一个字段order_id,我们定义为唯一索引。2.代码编写我们主要实现了订阅取消方法cancelOrder:packagecom.example.idempotentmysql.service.impl;importcom.example.idempotentmysql.bean.IdempotentValidate;importcom.example.idempotentmysql.bean.OrderInfo;importcom.example.idempotentmysql.bean.ProductInfo;导入com.example.idempotentmysql.bean.UserInfo;导入com.example.idempotentmysql.repository.IdempotentValidateRepository;导入com.example.idempotentmysql.repository.OrderInfoRepository;导入com.example.idempotentmysql.repository.ProductInfoRepository;导入com.example.idempotentmysql.repository.UserInfoRepository;导入com.example.idempotentmysql.service.OrderService;导入org.slf4j.Logger;导入org.slf4j.LoggerFactory;导入org.springframework.stereotype.Service;导入javax.annotation.Resource;importjava.util.Optional;/***预订单服务**@authorhongcunlin*/@ServicepublicclassOrderServiceImplimplementsOrderService{/***日志*/privatestaticfinalLoggerLOGGER=LoggerFactory.get记录器(OrderServiceImpl.class);/***用户存储库*/@ResourceprivateUserInfoRepositoryuserInfoRepository;/***产品存储库*/@ResourceprivateProductInfoRepositoryproductInfoRepository;/***订单存储库*/@ResourceprivateOrderInfoRepositoryorder;/InfoRepository***幂等性检查*/@ResourceprivateIdempotentValidateRepositoryidempotentValidateRepository;/***取消订单(带幂等性检查)**@paramorderId订单id*/@OverridepublicvoidcancelOrder(LongorderId){//1.幂等验证try{IdempotentValidateidempotentValidate=newIdempotentValidate();idempotentValidate.setOrderId(orderId);idempotentValidateRepository.save(idempotentValidate);}catch(Exceptione){LOGGER.info("订单退款幂等");返回;}//2.退款OptionalorderInfoOptional=orderInfoRepository.findById(orderId);如果(orderInfoOptional.isPresent()){OrderInfoorderInfo=orderInfoOptional.get();OptionaluserInfoOptional=userInfoRepository.findById(orderInfo.getUserId());findById(orderInfo.getProductId());如果(userInfoOptional.isPresent()&&productInfoOptional.isPresent()){UserInfouserInfo=userInfoOptional.get();ProductInfoproductInfo=productInfoOptional.get();userInfo.getMoney(用户信息);幂等表先用订单id插入。如果插入成功,则表示第一次取消订单,执行下面的退款逻辑;如果插入失败,说明之前已经执行了退款逻辑,我们提前返回。通过做下面的退款操作,实现了订单退款的幂等性。3、测试我们三次取消订单:packagecom.example.idempotentmysql.service;导入com.example.idempotentmysql.bean.OrderInfo;导入org.junit.jupiter.api.Test;导入org.springframework.boot。test.context.SpringBootTest;importjavax.annotation.Resource;@SpringBootTestpublicclassOrderServiceTest{@ResourceprivateOrderServiceorderService;@TestpublicvoidcancelOrderTest(){orderService.cancelOrder(6L);orderService.cancelOrder(6L);orderService.cancelOrder(6L);}}可以看出只有第一次退款成功,后面两次触发幂等,退款失败,符合我们的预期。还有许多其他方法可以实现幂等性。基于MySQL的UNIQUEKEY的实现方案实现起来比较简单,只适用于业务简单,并发度不高的场景。原因是MySQL的QPS有限,MySQL作为系统最底层的应用,来不及了。如果最终幂等返回,会浪费前端业务处理消耗的资源。本文代码已经上传到github,需要的同学可以下载参考:https://github.com/larger5/idempotent-mysql