IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> 通过Redis实现分布式锁 代码分享。 -> 正文阅读

[大数据]通过Redis实现分布式锁 代码分享。

Redis实现分布式锁的作用和意义,可以参考这篇文章:https://zhuanlan.zhihu.com/p/268290754

代码的话,不废话,直接看我在项目中用的。
一.配置RedisTemplate对象
我是基于RedisTemplate对象来实现分布式锁的,而不是jedis。

package com.wuyouhu.common.redis.configure;

import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * redis配置
 * 
 * @author lele
 */
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport
{
    @Bean
    @SuppressWarnings(value = { "unchecked", "rawtypes", "deprecation" })
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory)
    {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);

        FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class);

        ObjectMapper mapper = new ObjectMapper();
        mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        serializer.setObjectMapper(mapper);

        template.setValueSerializer(serializer);
        // 使用StringRedisSerializer来序列化和反序列化redis的key值
        template.setKeySerializer(new StringRedisSerializer());
        template.afterPropertiesSet();
        return template;
    }
}

二.redis分布式锁Entity类

package com.wuyouhu.common.redis.domian;

/**
 * redis分布式锁Entity类
 * 
 * @author lele
 */
public class RedisLockEntity {
    private String lockKey;
    private String requestId;

    public RedisLockEntity() {
    }

    public String getLockKey() {
        return lockKey;
    }

    public void setLockKey(String lockKey) {
        this.lockKey = lockKey;
    }

    public String getRequestId() {
        return requestId;
    }

    public void setRequestId(String requestId) {
        this.requestId = requestId;
    }

    @Override
    public String toString() {
        return "RedisLockEntity{" +
                "lockKey='" + lockKey + '\'' +
                ", requestId='" + requestId + '\'' +
                '}';
    }
}

三.lua解锁脚本代码
放在模块的resources目录下。

if redis.call('get',KEYS[1]) == ARGV[1] then
    return redis.call('del',KEYS[1])
else
    return 0
end

![在这里插入图片描述](https://img-blog.csdnimg.cn/af03ec8c488948fa9f5453192a9eeeea.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5ZCb44KS6KaL44Gk44GR44Gm,size_20,color_FFFFFF,t_70,g_se,x_16
在这里插入图片描述

四.redis分布式锁工具类

package com.wuyouhu.common.redis.service;

import java.util.*;
import java.util.concurrent.TimeUnit;

import com.wuyouhu.common.redis.domian.RedisLockEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;

/**
 * spring redis 分布式锁工具类
 *
 * @author lele
 **/
@SuppressWarnings(value = { "unchecked", "rawtypes" })
@Component
public class RedisService
{
    private final static Logger logger = LoggerFactory
            .getLogger(RedisService.class);

    @Autowired
    public RedisTemplate redisTemplate;

    /**
     * 加锁,自旋重试三次
     *
     * @param redisLockEntity 锁实体
     * @return
     */
    public boolean lock(RedisLockEntity redisLockEntity) {
        boolean locked = false;
        int tryCount = 3;
        while (!locked && tryCount > 0) {
            locked = redisTemplate.opsForValue().setIfAbsent(redisLockEntity.getLockKey(), redisLockEntity.getRequestId(), 2, TimeUnit.MINUTES);
            tryCount--;
            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                logger.error("线程被中断" + Thread.currentThread().getId(),e);
            }
        }
        return locked;
    }

    /**
     * 非原子解锁,可能解别人锁,不安全
     *
     * @param redisLockEntity
     * @return
     */
    public boolean unlock(RedisLockEntity redisLockEntity) {
        if (redisLockEntity == null || redisLockEntity.getLockKey() == null || redisLockEntity.getRequestId() == null)
            return false;
        boolean releaseLock = false;
        String requestId = (String) redisTemplate.opsForValue().get(redisLockEntity.getLockKey());
        if (redisLockEntity.getRequestId().equals(requestId)) {
            releaseLock = redisTemplate.delete(redisLockEntity.getLockKey());
        }
        return releaseLock;
    }

    /**
     * 使用lua脚本解锁,不会解除别人锁
     *
     * @param redisLockEntity
     * @return
     */
    public boolean unlockLua(RedisLockEntity redisLockEntity) {
        if (redisLockEntity == null || redisLockEntity.getLockKey() == null || redisLockEntity.getRequestId() == null)
            return false;
        DefaultRedisScript<Long> redisScript = new DefaultRedisScript();
        //用于解锁的lua脚本位置
        redisScript.setLocation(new ClassPathResource("unlock.lua"));
        redisScript.setResultType(Long.class);
        //没有指定序列化方式,默认使用上面配置的
        Object result = redisTemplate.execute(redisScript, Arrays.asList(redisLockEntity.getLockKey()), redisLockEntity.getRequestId());
        return result.equals(Long.valueOf(1));
    }


}

五.分布式锁业务使用示例

package com.wuyouhu.templates.controller;

import com.wuyouhu.common.redis.domian.RedisLockEntity;
import com.wuyouhu.common.redis.service.RedisService;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;


/**
 * 分布式锁业务
 */

@RestController
@RequestMapping("/seat")
public class SeatController extends BaseController {

    @Autowired
    private RedisService redisService;

    /**
     * 更新订单业务。。。。
     * @return
     */
    @GetMapping(value = "/testRedisLock")
    public String testRedislock1() {
        System.out.println("start....lock");
        RedisLockEntity redisLockEntity = new RedisLockEntity();
        redisLockEntity.setLockKey("lockkey");
        redisLockEntity.setRequestId("1");
        boolean lock = redisService.lock(redisLockEntity);
        if (lock){//如果上锁成功
            System.out.println("lock success!");
           	
           	// 此时只有该拿到锁(上锁)的实例可以更新订单数量......
            // 业务代码
            
       		
       		this.testRedisUnlock2()// 更新订单完成后,释放锁。
        } else { // 如果上锁不成功
            System.out.println("lock fail!");

			//此时没拿到锁,则不能更新订单数量。可以采取自旋直到抢到锁为止再去更新订单数量;或者是执行其它业务。
            // 业务代码 
        }
        System.out.println("end.....lock");
        return "success";
    }

     /**
     * 释放锁业务
     * @return
     */
    public String testRedisUnlock2() {
        System.out.println("start....unlock");
        RedisLockEntity redisLockEntity = new RedisLockEntity();
        redisLockEntity.setLockKey("lockkey");
        redisLockEntity.setRequestId("1");
            boolean unlock = redisService.unlockLua(redisLockEntity);
            if (unlock){
                System.out.println("unlock success!");
            } else {
                System.out.println("unlock fail!");
            }

        System.out.println("end....unlock");
        return "success";
    }


}

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2021-12-14 16:00:53  更:2021-12-14 16:01:18 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 11:01:11-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码