分布式锁实战(三)基于Redis的分布式锁


除了之前我们数据层面的锁,业界上还包括基于Redis的原子操作实现分布式锁。以及Zoopkeeper的临时节点,和Watcher机制实现分布式锁。
本章将讲述Redis的原子性操作实现分布式锁

Redis复习

在之前抢红包的模块中,其实setnx就是原子性操作,并且它是以key-value存储的数据结构,具有丰富的数据类型,并且应用场景非常适合高并发
在这里插入图片描述

分布式锁的实现流程和原理

在这里插入图片描述
上述得出结论3个核心
1.第一个核心是静心设计一个跟业务相关的key,用于充当setnx的命令
2.第二个核心是采用setnx 和 expire命令,用于获取对共享资源的锁
3.操作完成后释放该锁

基于Redis实战实现分布式锁

在前面章节中,我们用的是抢红包,本章节我们采用用户注册,流程如下
1.后端首先判断用户名是否被注册,没有注册就插入到用户注册表,并返回注册,如果注册了就返回注册失败
在这里插入图片描述
高并发产生的问题
如果用户疯狂点击注册,那么就有可能生成两个一样用户名的用户,下面实战演示这个场景

数据库设计

CREATE TABLE user_reg (
 id int(11) NOT NULL AUTO_INCREMENT,
 user_name varchar(255) NOT NULL COMMENT '用户名',
 password varchar(255) NOT NULL COMMENT '密码',
 create_time datetime DEFAULT NULL COMMENT '创建时间',
 PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户注册信息表';
package com.learn.boot.controller;

import com.learn.boot.dto.UserAccountDto;
import com.learn.boot.dto.UserLoginDto;
import com.learn.boot.mapper.redis.user.UserRegMapper;
import com.learn.boot.model.UserAccount;
import com.learn.boot.model.UserAccountRecord;
import com.learn.boot.model.UserReg;
import com.learn.boot.resultVo.ResultVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.math.BigDecimal;
import java.util.Date;

/**
 * 用户注册
 */
@RestController
public class LoginController {

    //定义Redis的操作组件实例
    @Autowired
    private StringRedisTemplate stringRedisTemplate;


    @Autowired
    private UserRegMapper userRegMapper;
    @RequestMapping("/login")
    public ResultVo login(@RequestBody UserLoginDto model, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            return ResultVo.error("参数异常");
        }

        // 判断用户名是否被注册过
        UserReg userReg = userRegMapper.selectByUserName(model.getUserName());
        if (userReg == null) {
            UserReg insertUserReg = new UserReg(){
                {
                    setCreateTime(new Date());
                    setPassword(model.getPassword());
                    setUserName(model.getUserName());
                }
            };
            userRegMapper.insertSelective(insertUserReg);
        }
        return ResultVo.error("提现异常");
    }

}

发现高并发下出现问题
在这里插入图片描述

    @Autowired
    private UserRegMapper userRegMapper;
    @RequestMapping("/login")
    public ResultVo login(@RequestBody UserLoginDto model, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            return ResultVo.error("参数异常");
        }

        // 先加分布式锁
        StringBuffer sb = new StringBuffer(model.getUserName());
        sb.append("_lock");
        String value = "11";
        // 获取操作Key的ValueOperations实例
        ValueOperations valueOperations=stringRedisTemplate.opsForValue();
        Boolean res = (Boolean) valueOperations.setIfAbsent(sb.toString(),value);
        // 具体应根据实际情况而定
        stringRedisTemplate.expire(sb.toString(),2L, TimeUnit.SECONDS);
        // 判断用户名是否被注册过
        if (!res) {
            log.info("{}注册失败",model.getUserName());
            return ResultVo.error("用户信息已存在");
        }
        UserReg userReg = userRegMapper.selectByUserName(model.getUserName());
        if (userReg == null) {
            UserReg insertUserReg = new UserReg(){
                {
                    setCreateTime(new Date());
                    setPassword(model.getPassword());
                    setUserName(model.getUserName());
                }
            };
            userRegMapper.insertSelective(insertUserReg);
            log.info("{}注册成功",model.getUserName());
            // 执行完业务记得删除
            stringRedisTemplate.delete(sb.toString());
            return ResultVo.success("注册成功");
        }
        return null;
    }

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值