日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢(xún)
選擇下列產(chǎn)品馬上在線(xiàn)溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
互聯(lián)網(wǎng)業(yè)務(wù)冪等性實(shí)現(xiàn)之基于MySQL

背景

在互聯(lián)網(wǎng)業(yè)務(wù)領(lǐng)域中,我們經(jīng)常會(huì)遇到應(yīng)用到請(qǐng)求冪等性問(wèn)題,即多次重復(fù)請(qǐng)求,所得到的結(jié)果,和一次請(qǐng)求一致。

平武網(wǎng)站建設(shè)公司創(chuàng)新互聯(lián)公司,平武網(wǎng)站設(shè)計(jì)制作,有大型網(wǎng)站制作公司豐富經(jīng)驗(yàn)。已為平武上千多家提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\外貿(mào)網(wǎng)站制作要多少錢(qián),請(qǐng)找那個(gè)售后服務(wù)好的平武做網(wǎng)站的公司定做!

以某互聯(lián)網(wǎng)電商的取消訂單為例子,當(dāng)訂單取消,需要返回給消費(fèi)者下單所消費(fèi)的虛擬產(chǎn)品,如優(yōu)惠券、紅包、京豆等。通過(guò)冪等形式,確保返還給消費(fèi)者的權(quán)益不多、不少。

那冪等性具體開(kāi)發(fā)是怎么實(shí)現(xiàn)的呢?本文帶來(lái)基于MySQL的UNIQUE KEY的實(shí)現(xiàn)方案。

實(shí)現(xiàn)

眾所周知,UNIQUE KEY是數(shù)據(jù)庫(kù)中的唯一索引,數(shù)據(jù)庫(kù)的記錄中不允許有重復(fù)的值,我們可以利用這點(diǎn),在處理業(yè)務(wù)前,先進(jìn)行唯一索引數(shù)據(jù)(如訂單id)的插入操作:

  • 插入成功,說(shuō)明是第一次插入,正常處理業(yè)務(wù);
  • 插入失敗,說(shuō)明該業(yè)務(wù)邏輯已經(jīng)處理過(guò)了,不做處理,提前返回;

如此,即可實(shí)現(xiàn)冪等性。

1.數(shù)據(jù)庫(kù)設(shè)計(jì)

冪等性輔助表設(shè)計(jì)如下:

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;

其中的一個(gè)字段order_id,我們定義為唯一索引。

2.代碼編寫(xiě)

我們主要實(shí)現(xiàn)了訂單取消方法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;

/**
* 訂單服務(wù)
*
* @author hongcunlin
*/
@Service
public class OrderServiceImpl implements OrderService {
/**
* 日志
*/
private static final Logger LOGGER = LoggerFactory.getLogger(OrderServiceImpl.class);

/**
* 用戶(hù)repository
*/
@Resource
private UserInfoRepository userInfoRepository;

/**
* 商品repository
*/
@Resource
private ProductInfoRepository productInfoRepository;

/**
* 訂單repository
*/
@Resource
private OrderInfoRepository orderInfoRepository;

/**
* 冪等性校驗(yàn)
*/
@Resource
private IdempotentValidateRepository idempotentValidateRepository;

/**
* 取消訂單(帶冪等性校驗(yàn))
*
* @param orderId 訂單id
*/
@Override
public void cancelOrder(Long orderId) {
// 1.冪等性校驗(yàn)
try {
IdempotentValidate idempotentValidate = new IdempotentValidate();
idempotentValidate.setOrderId(orderId);
idempotentValidateRepository.save(idempotentValidate);
} catch (Exception e) {
LOGGER.info("訂單退款冪等");
return;
}

// 2.退款
Optional orderInfoOptional = orderInfoRepository.findById(orderId);
if (orderInfoOptional.isPresent()) {
OrderInfo orderInfo = orderInfoOptional.get();
Optional userInfoOptional = userInfoRepository.findById(orderInfo.getUserId());
Optional productInfoOptional = 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("訂單成功退款");
}
}

從代碼中可以看到,我們?cè)诔擞唵瓮丝钋?,冪等性表先拿訂單id進(jìn)行插入操作,若插入成功,說(shuō)明是第一次取消訂單,執(zhí)行下面的退款邏輯;

若插入失敗,說(shuō)明之前已經(jīng)進(jìn)行過(guò)退款邏輯了,我們提前返回,不做下面的退款操作。

如此,便實(shí)現(xiàn)了訂單退款的冪等性。

3.測(cè)試

我們對(duì)訂單進(jìn)行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次觸發(fā)冪等性,退款失敗,符合我們的預(yù)期。

其他

冪等性的實(shí)現(xiàn)方式還有很多種,基于MySQL的UNIQUE KEY的實(shí)現(xiàn)方案,實(shí)現(xiàn)起來(lái)相當(dāng)簡(jiǎn)單,僅適合業(yè)務(wù)簡(jiǎn)單,并發(fā)量不高的場(chǎng)景。原因是MySQL的qps有限,且MySQL作為系統(tǒng)的最底層的應(yīng)用,過(guò)于后置,如果最終冪等返回,比較浪費(fèi)前置的業(yè)務(wù)處理所消耗的資源。

本文代碼已經(jīng)上傳到github上了,有需要的同學(xué)可以下載參考:https://github.com/larger5/idempotent-mysql


網(wǎng)頁(yè)名稱(chēng):互聯(lián)網(wǎng)業(yè)務(wù)冪等性實(shí)現(xiàn)之基于MySQL
本文網(wǎng)址:http://www.5511xx.com/article/cohdhij.html