互联网业务幂等性实现之基于MySQL

发布时间:2025-05-11 11:40:53 作者:益华网络 来源:147小编 浏览量(1) 点赞(1)
摘要:背景 在互联网业务领域中,我们经常会遇到应用到请求幂等性问题,即多次重复请求,所得到的结果,和一次请求一致。 以某互联网电商的取消订单为例子,当订单取消,需要返回给消费者下单所消费的虚拟产品,如优惠券、红包、京豆等。通过幂等形式,确保返还给消费者的权益不多、不少。

背景

在互联网业务领域中,我们经常会遇到应用到请求幂等性问题,即多次重复请求,所得到的结果,和一次请求一致。

以某互联网电商的取消订单为例子,当订单取消,需要返回给消费者下单所消费的虚拟产品,如优惠券、红包、京豆等。通过幂等形式,确保返还给消费者的权益不多、不少。

那幂等性具体开发是怎么实现的呢?本文带来基于MySQL的UNIQUE KEY的实现方案。

实现

众所周知,UNIQUE KEY是数据库中的唯一索引,数据库的记录中不允许有重复的值,我们可以利用这点,在处理业务前,先进行唯一索引数据(如订单id)的插入操作:

插入成功,说明是第一次插入,正常处理业务;插入失败,说明该业务逻辑已经处理过了,不做处理,提前返回;

如此,即可实现幂等性。

1.数据库设计

幂等性辅助表设计如下:

CREATE TABLE `idempotent_validate` (

`id` bigint NOT NULL,

`create_time` time DEFAULT NULL,

`order_id` bigint DEFAULT NULL,

PRIMARY KEY (`id`),

UNIQUE KEY `UK_orssam7fgn4uj0lo2sn4on6vg` (`order_id`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

其中的一个字段order_id,我们定义为唯一索引。

2.代码编写

我们主要实现了订单取消方法cancelOrder:

package com.example.idempotentmysql.service.impl;

import com.example.idempotentmysql.bean.IdempotentValidate;

import com.example.idempotentmysql.bean.OrderInfo;

import com.example.idempotentmysql.bean.ProductInfo;

import com.example.idempotentmysql.bean.UserInfo;

import com.example.idempotentmysql.repository.IdempotentValidateRepository;

import com.example.idempotentmysql.repository.OrderInfoRepository;

import com.example.idempotentmysql.repository.ProductInfoRepository;

import com.example.idempotentmysql.repository.UserInfoRepository;

import com.example.idempotentmysql.service.OrderService;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import java.util.Optional;

/**

* 订单服务

*

* @author hongcunlin

*/

@Service

public class OrderServiceImpl implements OrderService {

/**

* 日志

*/

private static final Logger LOGGER = LoggerFactory.getLogger(OrderServiceImpl.class);

/**

* 用户repository

*/

@Resource

private UserInfoRepository userInfoRepository;

/**

* 商品repository

*/

@Resource

private ProductInfoRepository productInfoRepository;

/**

* 订单repository

*/

@Resource

private OrderInfoRepository orderInfoRepository;

/**

* 幂等性校验

*/

@Resource

private IdempotentValidateRepository idempotentValidateRepository;

/**

* 取消订单(带幂等性校验)

*

* @param orderId 订单id

*/

@Override

public void cancelOrder(Long orderId) {

// 1.幂等性校验

try {

IdempotentValidate idempotentValidate = new IdempotentValidate();

idempotentValidate.setOrderId(orderId);

idempotentValidateRepository.save(idempotentValidate);

} catch (Exception e) {

LOGGER.info("订单退款幂等");

return;

}

// 2.退款

OptionalorderInfoOptional = orderInfoRepository.findById(orderId);

if (orderInfoOptional.isPresent()) {

OrderInfo orderInfo = orderInfoOptional.get();

OptionaluserInfoOptional = userInfoRepository.findById(orderInfo.getUserId());

OptionalproductInfoOptional = productInfoRepository.findById(orderInfo.getProductId());

if (userInfoOptional.isPresent() && productInfoOptional.isPresent()) {

UserInfo userInfo = userInfoOptional.get();

ProductInfo productInfo = productInfoOptional.get();

userInfo.setMoney(userInfo.getMoney().add(productInfo.getPrice()));

userInfoRepository.save(userInfo);

}

}

LOGGER.info("订单成功退款");

}

}

从代码中可以看到,我们在除了订单退款前,幂等性表先拿订单id进行插入操作,若插入成功,说明是第一次取消订单,执行下面的退款逻辑;

若插入失败,说明之前已经进行过退款逻辑了,我们提前返回,不做下面的退款操作。

如此,便实现了订单退款的幂等性。

3.测试

我们对订单进行3次取消操作:

package com.example.idempotentmysql.service;

import com.example.idempotentmysql.bean.OrderInfo;

import org.junit.jupiter.api.Test;

import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;

@SpringBootTest

public class OrderServiceTest {

@Resource

private OrderService orderService;

@Test

public void cancelOrderTest() {

orderService.cancelOrder(6L);

orderService.cancelOrder(6L);

orderService.cancelOrder(6L);

}

}

可以看到,只有第一次是退款成功的,后面2次触发幂等性,退款失败,符合我们的预期。

其他

幂等性的实现方式还有很多种,基于MySQL的UNIQUE KEY的实现方案,实现起来相当简单,仅适合业务简单,并发量不高的场景。原因是MySQL的qps有限,且MySQL作为系统的最底层的应用,过于后置,如果最终幂等返回,比较浪费前置的业务处理所消耗的资源。

本文代码已经上传到github上了,有需要的同学可以下载参考:https://github.com/larger5/idempotent-mysql

二维码

扫一扫,关注我们

声明:本文由【益华网络】编辑上传发布,转载此文章须经作者同意,并请附上出处【益华网络】及本页链接。如内容、图片有任何版权问题,请联系我们进行处理。

感兴趣吗?

欢迎联系我们,我们愿意为您解答任何有关网站疑难问题!

您身边的【网站建设专家】

搜索千万次不如咨询1次

主营项目:网站建设,手机网站,响应式网站,SEO优化,小程序开发,公众号系统,软件开发等

立即咨询 15368564009
在线客服
嘿,我来帮您!