冪等性

1.冪等性

冪等性是分布式環(huán)境下常見(jiàn)的問(wèn)題;冪等性指的是多次操作,結(jié)果是一致的。(多次操作數(shù)據(jù)庫(kù)數(shù)據(jù)是一致的。)
常見(jiàn)的解決冪等性的方式有以下:
1.唯一索引;保證插入的數(shù)據(jù)只有一條;
2.token機(jī)制;每次接口請(qǐng)求前先獲取一個(gè)token,然后再下次請(qǐng)求的時(shí)候在請(qǐng)求的header體中加上這個(gè)token,后臺(tái)進(jìn)行驗(yàn)證,如果驗(yàn)證通過(guò)刪除token,下次請(qǐng)求再次判斷token
3.悲觀鎖或者樂(lè)觀鎖,悲觀鎖可以保證每次for update的時(shí)候其他sql無(wú)法update數(shù)據(jù)(在數(shù)據(jù)庫(kù)引擎是innodb的時(shí)候,select的條件必須是唯一索引,防止鎖全表)【分布鎖思路】
4.先查詢后判斷,首先通過(guò)查詢數(shù)據(jù)庫(kù)是否存在數(shù)據(jù),如果存在證明已經(jīng)請(qǐng)求過(guò)了,直接拒絕該請(qǐng)求,如果沒(méi)有存在,就證明是第一次進(jìn)來(lái),直接放行。

2.redis實(shí)現(xiàn)冪等性

image.png

2.1 搭建redis,編寫(xiě)操作redis的API

這一步?jīng)]啥好說(shuō)的,網(wǎng)上一大堆。一般你出來(lái)工作了,也不會(huì)讓你搭建。項(xiàng)目都已經(jīng)搭好了,用就完事了。

2.2 token服務(wù)



public interface TokenService {

    /**
     * 生成token
     * @return 返回生成的token
     */
    String createToken();

    /**
     * 校驗(yàn)token
     * @param httpServletRequest http請(qǐng)求
     * @return 校驗(yàn)token結(jié)果
     * @throws Exception 拋出異常
     */
    boolean checkToken(HttpServletRequest httpServletRequest) throws Exception;

}


import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.UUID;

@Service
public class TokenServiceImpl implements TokenService {
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    private static final String TOKEN_PREFIX = "token_prefix";

    private static final String TOKEN_NAME = "check_token";

    @Override
    public String createToken() {
        String str = UUID.randomUUID().toString();
        StringBuilder token = new StringBuilder();
        try {
            token.append(TOKEN_PREFIX).append(str);
            stringRedisTemplate.opsForValue().set(token.toString(), token.toString(), 10000L);
            boolean notEmpty = StringUtils.isNotBlank(token.toString());
            if (notEmpty) {
                return token.toString();
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

    @Override
    public boolean checkToken(HttpServletRequest request) throws Exception {
        String token = request.getHeader(TOKEN_NAME);
        if (StringUtils.isBlank(token)) {
            token = request.getParameter(TOKEN_NAME);
            if (StringUtils.isBlank(token)) {
                throw new OperationException("token不存在");
            }
        }
        String isExist = stringRedisTemplate.opsForValue().get(token);
        if (StringUtils.isBlank(isExist)){
            throw new OperationException("token不存在");
        }
        Boolean remove = stringRedisTemplate.delete(token);
        if (!remove) {
            throw new OperationException("token不存在");
        }
        return true;
    }
}

主要的代碼如上;這是對(duì)于Web環(huán)境的;如果是服務(wù)之間的調(diào)用。比如dubbo,fegin接口之間的調(diào)用??梢詫oken作為參數(shù)傳給服務(wù)端進(jìn)行校驗(yàn)??傮w來(lái)說(shuō),思路還是比較簡(jiǎn)單的。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容