欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Redis實(shí)現(xiàn)短信登錄的企業(yè)實(shí)戰(zhàn)

 更新時(shí)間:2022年07月20日 15:00:01   作者:Super_Leng  
本文主要介紹了Redis實(shí)現(xiàn)短信登錄的企業(yè)實(shí)戰(zhàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

一、導(dǎo)入黑馬點(diǎn)評(píng)項(xiàng)目

黑馬點(diǎn)評(píng)項(xiàng)目主要包括以下功能:

這一章主要介紹短信登錄功能,短信登錄功能是基于Redis的共享session實(shí)現(xiàn)的

1. 導(dǎo)入SQL

需要項(xiàng)目資料的私信我

其中的表有:

  • tb_user:用戶表
  • tb_user_info:用戶詳情表
  • tb_shop:商戶信息表
  • tb_shop_type:商戶類型表
  • tb_blog:用戶日記表(達(dá)人探店日記)
  • tb_follow:用戶關(guān)注表
  • tb_voucher:優(yōu)惠券表
  • tb_voucher_order:優(yōu)惠券的訂單表

注意:Mysql的版本采用5.7及以上版本

2. 前后端分離

3. 導(dǎo)入后端項(xiàng)目

3.1 將后端項(xiàng)目導(dǎo)入到 Idea 中

3.2 注意:修改application.yaml文件中的mysql、redis地址信息 將mysql、redis地址信息修改為自己的信息

3.3 啟動(dòng)項(xiàng)目 啟動(dòng)項(xiàng)目后,在瀏覽器訪問:http://localhost:8081/shop-type/list ,如果可以看到數(shù)據(jù)則證明運(yùn)行沒有問題

4. 導(dǎo)入前端項(xiàng)目

4.1 導(dǎo)入nginx文件夾 將nginx文件夾復(fù)制到任意目錄,要確保該目錄不包含中文、特殊字符和空格,例如:

4.2 運(yùn)行前端項(xiàng)目 在nginx所在目錄下打開一個(gè)CMD窗口,輸入命令啟動(dòng)nginx:

start nginx.exe

打開chrome瀏覽器,在空白頁面點(diǎn)擊鼠標(biāo)右鍵,選擇檢查,即可打開開發(fā)者工具:

然后訪問: http://127.0.0.1:8080 ,即可看到頁面:

二、基于Session實(shí)現(xiàn)登錄流程

  • 后端將生成的驗(yàn)證碼和用戶信息保存到session中,并將sessionId返回給前端保存到cookie中
  • 用戶登錄時(shí),會(huì)攜帶cookie向后端發(fā)起請(qǐng)求,后端進(jìn)行校驗(yàn)時(shí),從cookie中獲取sessionId,通過sessionId可以從session中獲取用戶信息并保存到ThreadLocal中
  • 后續(xù)每個(gè)線程都有一份ThreadLocal中的用戶副本信息,不同線程拿到用戶信息后可以實(shí)現(xiàn)不同的操作,從而起到線程隔離作用

1. 發(fā)送短信驗(yàn)證碼

主要代碼:

@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {

    @Resource
    private IUserService userService;

    /**
     * 發(fā)送手機(jī)驗(yàn)證碼
     */
    @PostMapping("code")
    public Result sendCode(@RequestParam("phone") String phone, HttpSession session) {
        // 發(fā)送短信驗(yàn)證碼并保存驗(yàn)證碼
        return userService.sendCode(phone, session);
    }
}    
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Override
    public Result sendCode(String phone, HttpSession session) {
        // 1.使用工具類校驗(yàn)手機(jī)號(hào)
        if (RegexUtils.isPhoneInvalid(phone)) {
            // 2.如果不符合,返回錯(cuò)誤信息
            return Result.fail("手機(jī)號(hào)格式錯(cuò)誤!");
        }
        // 3.符合,生成驗(yàn)證碼
        String code = RandomUtil.randomNumbers(6);

        // 4.保存驗(yàn)證碼到 session
        session.setAttribute("code",code);

        // 5.模擬發(fā)送驗(yàn)證碼
        log.debug("發(fā)送短信驗(yàn)證碼成功,驗(yàn)證碼:{}", code);
        // 返回ok
        return Result.ok();
    }
}

2. 短信驗(yàn)證碼登錄、注冊(cè)

主要代碼:

UserController

/**
 * 登錄功能
 * @param loginForm 登錄參數(shù),包含手機(jī)號(hào)、驗(yàn)證碼;或者手機(jī)號(hào)、密碼
 */
@PostMapping("/login")
public Result login(@RequestBody LoginFormDTO loginForm, HttpSession session){
    // 實(shí)現(xiàn)登錄功能
    return userService.login(loginForm, session);
}

UserServiceImpl

@Override
public Result login(LoginFormDTO loginForm, HttpSession session) {
    // 1.校驗(yàn)手機(jī)號(hào)
    String phone = loginForm.getPhone();
    if (RegexUtils.isPhoneInvalid(phone)) {
        // 如果不符合,返回錯(cuò)誤信息
        return Result.fail("手機(jī)號(hào)格式錯(cuò)誤!");
    }

    // 2.校驗(yàn)驗(yàn)證碼
    Object cacheCode = session.getAttribute("code");
    String code = loginForm.getCode();
    if (cacheCode == null || !cacheCode.toString().equals(code)) {
        // 3.驗(yàn)證碼不一致,則報(bào)錯(cuò)
        return Result.fail("驗(yàn)證碼錯(cuò)誤");
    }

    // 4.驗(yàn)證碼一致,根據(jù)手機(jī)號(hào)查詢用戶
    User user = query().eq("phone", phone).one();

    // 5.判斷用戶是否存在
    if (user == null) {
        // 6.用戶不存在,則創(chuàng)建用戶并保存
        user = createUserWithPhone(phone);
    }

    // 7.保存用戶信息到session中,UserDTO只包含簡(jiǎn)單的用戶信息,
    // 而不是完整的User,這樣可以隱藏用戶的敏感信息(例如:密碼等),還能減少內(nèi)存使用
    session.setAttribute("user", BeanUtil.copyProperties(user, UserDTO.class));

    // 8.返回ok
    return Result.ok();
}

private User createUserWithPhone(String phone) {
    // 1.創(chuàng)建用戶
    User user = new User();
    user.setPhone(phone);
    // 隨機(jī)設(shè)置昵稱 user_mrkuw05lok
    user.setNickName(SystemConstants.USER_NICK_NAME_PREFIX + RandomUtil.randomString(10));
    // 2.保存用戶
    save(user);
    return user;
}

3. 登錄驗(yàn)證功能

用戶請(qǐng)求登錄時(shí),會(huì)攜帶cookie,cookie中包含JSEESIONID

為了避免用戶請(qǐng)求每個(gè)controller時(shí),每次都去校驗(yàn)用戶信息,所以可以加攔截器

攔截器只需在用戶請(qǐng)求訪問時(shí),校驗(yàn)一次后將用戶信息保存到ThreadLocal中,供后續(xù)線程使用

主要代碼:

在工具類中編寫ThreadLocal

public class UserHolder {
    private static final ThreadLocal<UserDTO> tl = new ThreadLocal<>();

    public static void saveUser(UserDTO user){
        tl.set(user);
    }

    public static UserDTO getUser(){
        return tl.get();
    }

    public static void removeUser(){
        tl.remove();
    }
}

在工具類中編寫登錄攔截器

public class LoginInterceptor implements HandlerInterceptor {

    /**
     * 前置攔截
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 1.獲取session
        HttpSession session = request.getSession();
        // 2.獲取session中的用戶
        Object user = session.getAttribute("user");
        // 3.判斷用戶是否存在
        if(user == null){
            // 4.不存在,攔截,返回401狀態(tài)碼
            response.setStatus(401);
            return false;
        }
        // 5.存在,保存用戶信息到ThreadLocal
        UserHolder.saveUser((User)user);
        // 6.放行
        return true;
    }

    /**
     * 后置攔截器
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
        Object handler, Exception ex) throws Exception {
        // 請(qǐng)求結(jié)束后移除用戶,防止ThreadLocal造成內(nèi)存泄漏
        UserHolder.removeUser();
    }
}

在配置類中添加攔截器配置類

@Configuration
public class MvcConfig implements WebMvcConfigurer {

    /**
     * 添加攔截器
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 登錄攔截器
        registry.addInterceptor(new LoginInterceptor())
            // 排除不需要攔截的路徑
            .excludePathPatterns(
                "/shop/**",
                "/voucher/**",
                "/shop-type/**",
                "/upload/**",
                "/blog/hot",
                "/user/code",
                "/user/login"
            );
    }
}

UserController

@GetMapping("/me")
 public Result me(){
     // 獲取當(dāng)前登錄的用戶并返回
     UserDTO user = UserHolder.getUser();
     return Result.ok(user);
 }

三、集群的session共享問題

四、基于Redis實(shí)現(xiàn)共享session的登錄功能

1. 選擇合適的數(shù)據(jù)結(jié)構(gòu)存入Redis

  • 手機(jī)號(hào)作為key,String類型的驗(yàn)證碼作為value
  • 用戶登錄時(shí)正好會(huì)提交手機(jī)號(hào),方便通過Redis進(jìn)行校驗(yàn)驗(yàn)證碼

token作為key,Hash類型的用戶信息作為value

后端校驗(yàn)成功后,會(huì)返回token給前端,前端會(huì)將token保存到sessionStorage中(這是瀏覽器的存儲(chǔ)方式),以后前端每次請(qǐng)求都會(huì)攜帶token,方便后端通過Redis校驗(yàn)用戶信息

前端代碼:將后端返回的token保存到sessionStorage中

前端每次請(qǐng)求時(shí),都會(huì)通過攔截器將token設(shè)置到請(qǐng)求頭中,賦值給變量authorization,后端通過authorization獲取前端攜帶的token進(jìn)行校驗(yàn)

2. 發(fā)送短信驗(yàn)證碼

修改之前代碼,將驗(yàn)證碼存入Redis

@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public Result sendCode(String phone, HttpSession session) {
        // 1.使用工具類校驗(yàn)手機(jī)號(hào)
        if (RegexUtils.isPhoneInvalid(phone)) {
            // 2.如果不符合,返回錯(cuò)誤信息
            return Result.fail("手機(jī)號(hào)格式錯(cuò)誤!");
        }
        // 3.符合,生成驗(yàn)證碼
        String code = RandomUtil.randomNumbers(6);

        // 4.保存驗(yàn)證碼到 session
//        session.setAttribute("code",code);
        // 4.保存驗(yàn)證碼到 redis
        // "login:code:"是業(yè)務(wù)前綴,以"login:code:" + 手機(jī)號(hào)為key,過期時(shí)間2分鐘
        stringRedisTemplate.opsForValue().set(RedisConstants.LOGIN_CODE_KEY + phone, code, RedisConstants.LOGIN_CODE_TTL, TimeUnit.MINUTES);

        // 5.模擬發(fā)送驗(yàn)證碼
        log.debug("發(fā)送短信驗(yàn)證碼成功,驗(yàn)證碼:{}", code);
        // 返回ok
        return Result.ok();
    }
}    

3. 短信驗(yàn)證碼登錄、注冊(cè)

  • 修改之前代碼,從Redis獲取驗(yàn)證碼并校驗(yàn)
  • 隨機(jī)生成token,保存用戶信息到redis中,返回token
@Override
public Result login(LoginFormDTO loginForm, HttpSession session) {
    // 1.校驗(yàn)手機(jī)號(hào)
    String phone = loginForm.getPhone();
    if (RegexUtils.isPhoneInvalid(phone)) {
        // 如果不符合,返回錯(cuò)誤信息
        return Result.fail("手機(jī)號(hào)格式錯(cuò)誤!");
    }

//        // 2.校驗(yàn)驗(yàn)證碼
//        Object cacheCode = session.getAttribute("code");
//        String code = loginForm.getCode();
//        if (cacheCode == null || !cacheCode.toString().equals(code)) {
//            // 3.驗(yàn)證碼不一致,則報(bào)錯(cuò)
//            return Result.fail("驗(yàn)證碼錯(cuò)誤");
//        }

    // 2.從Redis獲取驗(yàn)證碼并校驗(yàn)
    String cacheCode = stringRedisTemplate.opsForValue().get(RedisConstants.LOGIN_CODE_KEY + phone);
    String code = loginForm.getCode();
    if (cacheCode == null || !cacheCode.equals(code)) {
        // 3.驗(yàn)證碼不一致,則報(bào)錯(cuò)
        return Result.fail("驗(yàn)證碼錯(cuò)誤");
    }

    // 4.驗(yàn)證碼一致,根據(jù)手機(jī)號(hào)查詢用戶
    User user = query().eq("phone", phone).one();

    // 5.判斷用戶是否存在
    if (user == null) {
        // 6.用戶不存在,則創(chuàng)建用戶并保存
        user = createUserWithPhone(phone);
    }

//        // 7.保存用戶信息到session中,UserDTO只包含簡(jiǎn)單的用戶信息,而不是完整的User,這樣可以隱藏用戶的敏感信息(例如:密碼等),還能減少內(nèi)存使用
//        session.setAttribute("user", BeanUtil.copyProperties(user, UserDTO.class));

    // 7.保存用戶信息到redis中
    // 7.1隨機(jī)生成token,作為登錄令牌
    // 使用hutool工具中的UUID,true表示不帶“-”符號(hào)的UUID
    String token = UUID.randomUUID().toString(true);
    
    // 7.2將User對(duì)象轉(zhuǎn)為Hash類型進(jìn)行存儲(chǔ)
    UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class);   
    // 由于使用的是stringRedisTemplate,所以存入的value中的值必須都是String類型的
    // 但是UserDTO中的id是Long類型的,所以進(jìn)行對(duì)象屬性拷貝時(shí),需要自定義實(shí)現(xiàn)轉(zhuǎn)換規(guī)則
     Map<String, Object> userMap = BeanUtil.beanToMap(userDTO, new HashMap<>(),CopyOptions.create().setIgnoreNullValue(true).setIgnoreNullValue(true).setFieldValueEditor((fieldName, fieldValue) -> fieldValue.toString()));
                                                     
    // 7.3存入redis, "login:token:"是業(yè)務(wù)前綴,以 "login:token:" + token作為key
    stringRedisTemplate.opsForHash().putAll(RedisConstants.LOGIN_USER_KEY + token, userMap);
    // 7.4設(shè)置token有效期,有效期為30分鐘
    stringRedisTemplate.expire(RedisConstants.LOGIN_USER_KEY + token, RedisConstants.LOGIN_USER_TTL, TimeUnit.MINUTES);

    // 8.返回token
    return Result.ok(token);
}

private User createUserWithPhone(String phone) {
    // 1.創(chuàng)建用戶
    User user = new User();
    user.setPhone(phone);
    // 隨機(jī)設(shè)置昵稱 user_mrkuw05lok
    user.setNickName(SystemConstants.USER_NICK_NAME_PREFIX + RandomUtil.randomString(10));
    // 2.保存用戶
    save(user);
    return user;
}

4. 解決token刷新問題

  • token刷新問題是指,用戶長時(shí)間不進(jìn)行界面操作時(shí),到了過期時(shí)間,token自動(dòng)失效;但是,用戶一旦進(jìn)行操作,就需要給token續(xù)期,即更新token過期時(shí)間
  • 為了解決token刷新問題,需要加2個(gè)攔截器
  • 第一個(gè)攔截器可以攔截所有請(qǐng)求,只要用戶有請(qǐng)求就刷新token,并保存用戶信息到ThreadLocal中
  • 第二個(gè)攔截器只對(duì)登錄請(qǐng)求進(jìn)行攔截,從ThreadLocal中獲取用戶信息進(jìn)行校驗(yàn)

刷新token的攔截器代碼:

public class RefreshTokenInterceptor implements HandlerInterceptor {

    // 因?yàn)長oginInterceptor不是通過Spring進(jìn)行管理的Bean,所以不能再LoginInterceptor中進(jìn)行注入StringRedisTemplate
    // 可以通過構(gòu)造方法傳入StringRedisTemplate
    private StringRedisTemplate stringRedisTemplate;

    public RefreshTokenInterceptor(StringRedisTemplate stringRedisTemplate) {
        this.stringRedisTemplate = stringRedisTemplate;
    }

    /**
     * 前置攔截
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//        // 1.獲取session
//        HttpSession session = request.getSession();
//        // 2.獲取session中的用戶
//        Object user = session.getAttribute("user");
//        // 3.判斷用戶是否存在
//        if(user == null){
//            // 4.不存在,攔截,返回401狀態(tài)碼
//            response.setStatus(401);
//            return false;
//        }
//        // 5.存在,保存用戶信息到ThreadLocal
//        UserHolder.saveUser((UserDTO)user);
//        // 6.放行
//        return true;

        // 1.獲取請(qǐng)求頭中的token
        String token = request.getHeader("authorization");
        if (StrUtil.isBlank(token)) {
            // 不存在,則攔截,返回401狀態(tài)碼
            response.setStatus(401);
            return false;
        }

        // 2.通過token獲取redis中的用戶
        Map<Object, Object> userMap = stringRedisTemplate.opsForHash()
            .entries(RedisConstants.LOGIN_USER_KEY + token);

        // 3.判斷用戶是否存在
        if (userMap.isEmpty()) {
            // 4.用戶不存在,則攔截,返回401狀態(tài)碼
            response.setStatus(401);
            return false;
        }

        // 5.將redis中Hash類型數(shù)據(jù)轉(zhuǎn)換成UserDTO對(duì)象
        UserDTO userDTO = BeanUtil.fillBeanWithMap(userMap, new UserDTO(), false);

        // 6.用戶存在,保存用戶信息到ThreadLocal
        UserHolder.saveUser(userDTO);

        // 7.刷新token有效期
        stringRedisTemplate.expire(RedisConstants.LOGIN_USER_KEY + token, RedisConstants.LOGIN_USER_TTL, TimeUnit.MINUTES);

        // 8.放行
        return true;
    }

    /**
     * 后置攔截器
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
        Object handler, Exception ex) throws Exception {
        // 請(qǐng)求結(jié)束后移除用戶,防止ThreadLocal造成內(nèi)存泄漏
        UserHolder.removeUser();
    }
}

登錄攔截器的代碼:

public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 1.判斷是否需要攔截(ThreadLocal中是否有用戶)
        if (UserHolder.getUser() == null) {
            // 沒有,需要攔截,設(shè)置狀態(tài)碼
            response.setStatus(401);
            // 攔截
            return false;
        }
        // 有用戶,則放行
        return true;
    }

}
@Configuration
public class MvcConfig implements WebMvcConfigurer {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 添加攔截器
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 登錄攔截器
        registry.addInterceptor(new LoginInterceptor())
            // 排除不需要攔截的路徑
            .excludePathPatterns(
                "/shop/**",
                "/voucher/**",
                "/shop-type/**",
                "/upload/**",
                "/blog/hot",
                "/user/code",
                "/user/login"
            ).order(1);

        // token刷新的攔截器,order越小,執(zhí)行優(yōu)先級(jí)越高,所以token刷新的攔截器先執(zhí)行
        registry.addInterceptor(new RefreshTokenInterceptor(stringRedisTemplate)).addPathPatterns("/**")
            .excludePathPatterns(
            // RefreshTokenInterceptor攔截器也需要放行"/user/code","/user/login",不然token過期后再重新登錄就會(huì)一直被攔截
                "/user/code",
                "/user/login")
            .order(0);
    }
}

到此這篇關(guān)于Redis實(shí)現(xiàn)短信登錄的企業(yè)實(shí)戰(zhàn)的文章就介紹到這了,更多相關(guān)Redis 短信登錄 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 用Redis實(shí)現(xiàn)微博關(guān)注關(guān)系

    用Redis實(shí)現(xiàn)微博關(guān)注關(guān)系

    在微博中,每一個(gè)用戶都會(huì)有一個(gè)關(guān)注列表,一個(gè)粉絲列表。用戶可以查看自己的關(guān)注,粉絲列表,也可以查看別人的關(guān)注,粉絲列表。并且,要展示列表里每個(gè)人與當(dāng)前查看者的關(guān)注狀態(tài)。
    2015-09-09
  • 使用Redis實(shí)現(xiàn)延時(shí)任務(wù)的解決方案

    使用Redis實(shí)現(xiàn)延時(shí)任務(wù)的解決方案

    這篇文章主要介紹了使用Redis實(shí)現(xiàn)延時(shí)任務(wù)的解決方案,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-08-08
  • Redis Sentinel的基本搭建

    Redis Sentinel的基本搭建

    這篇文章主要介紹了Redis Sentinel的使用,幫助大家更好的理解和學(xué)習(xí)使用Redis數(shù)據(jù)庫,感興趣的朋友可以了解下
    2021-03-03
  • redis常用命令、常見錯(cuò)誤、配置技巧等分享

    redis常用命令、常見錯(cuò)誤、配置技巧等分享

    這篇文章主要介紹了redis常用命令、常見錯(cuò)誤、配置技巧等分享,本文分享了12條redis知識(shí),需要的朋友可以參考下
    2015-02-02
  • Python交互Redis的實(shí)現(xiàn)

    Python交互Redis的實(shí)現(xiàn)

    本文主要介紹了Python交互Redis的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • redis連接被拒絕的解決方案

    redis連接被拒絕的解決方案

    這篇文章主要介紹了redis連接被拒絕的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • SpringBoot集成redis錯(cuò)誤問題及解決方法

    SpringBoot集成redis錯(cuò)誤問題及解決方法

    這篇文章主要介紹了SpringBoot集成redis錯(cuò)誤問題,本文給大家分享完美解決方法,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-02-02
  • Redis 執(zhí)行性能測(cè)試

    Redis 執(zhí)行性能測(cè)試

    這篇文章主要介紹了Redis 執(zhí)行性能測(cè)試的方法,文中講解非常細(xì)致,幫助大家更好的理解和學(xué)習(xí)redis,感興趣的朋友可以了解下
    2020-08-08
  • Redis分布式鎖Redlock的實(shí)現(xiàn)

    Redis分布式鎖Redlock的實(shí)現(xiàn)

    本文主要介紹了Redis分布式鎖Redlock的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • Redis的9種數(shù)據(jù)類型用法解讀

    Redis的9種數(shù)據(jù)類型用法解讀

    這篇文章主要介紹了Redis的9種數(shù)據(jù)類型用法及說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-02-02

最新評(píng)論