`

spring boot 利用redisson实现redis的分布式锁

 
阅读更多

利用redis实现分布式锁,网上搜索的大部分是使用java jedis实现的。

 

redis官方推荐的分布式锁实现为redisson http://ifeve.com/redis-lock/

 

以下为spring boot实现分布式锁的步骤

 

项目pom中需要添加官方依赖 我是1.8JDK固为

 

<!-- redisson -->
<dependency>
	<groupId>org.redisson</groupId>
	<artifactId>redisson</artifactId>
	<version>3.4.2</version>
</dependency>

 定义一个分布式锁的回调类

 

 

package com.example.demo.redis2;

/**
 * 分布式锁回调接口
 *
 * @author lk
 */
public interface DistributedLockCallback<T> {

    /**
     * 调用者必须在此方法中实现需要加分布式锁的业务逻辑
     *
     * @return
     */
    public T process();

    /**
     * 得到分布式锁名称
     *
     * @return
     */
    public String getLockName();
}

 分布式锁操作模板

 

 

package com.example.demo.redis2;
import java.util.concurrent.TimeUnit;

/**
 * 分布式锁操作模板
 *
 * @author lk
 */
public interface DistributedLockTemplate {
    /**
     * 使用分布式锁,使用锁默认超时时间。
     *
     * @param callback
     * @return
     */
    public <T> T lock(DistributedLockCallback<T> callback);

    /**
     * 使用分布式锁。自定义锁的超时时间
     *
     * @param callback
     * @param leaseTime 锁超时时间。超时后自动释放锁。
     * @param timeUnit
     * @return
     */
    public <T> T lock(DistributedLockCallback<T> callback, long leaseTime, TimeUnit timeUnit);
}

 

 

使用redisson最简单的Single instance mode实现分布式锁模板接口

 

package com.example.demo.redis2;

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;

import java.util.concurrent.TimeUnit;

/**
 * Single Instance mode 分布式锁模板
 *
 * @author lk
 */
public class SingleDistributedLockTemplate implements DistributedLockTemplate {
    private static final long     DEFAULT_TIMEOUT   = 5;
    private static final TimeUnit DEFAULT_TIME_UNIT = TimeUnit.SECONDS;

    private RedissonClient    redisson;

    public SingleDistributedLockTemplate() {
    }

    public SingleDistributedLockTemplate(RedissonClient redisson) {
        this.redisson = redisson;
    }

    @Override
    public <T> T lock(DistributedLockCallback<T> callback) {
        return lock(callback, DEFAULT_TIMEOUT, DEFAULT_TIME_UNIT);
    }

    @Override
    public <T> T lock(DistributedLockCallback<T> callback, long leaseTime, TimeUnit timeUnit) {
        RLock lock = null;
        try {
            lock = redisson.getLock(callback.getLockName());
            lock.lock(leaseTime, timeUnit);
            return callback.process();
        } finally {
            if (lock != null) {
                lock.unlock();
            }
        }
    }

    public void setRedisson(RedissonClient redisson) {
        this.redisson = redisson;
    }

}

创建可以被spring管理的 Bean

package com.example.demo.redis2;

import java.io.IOException;
import java.io.InputStream;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.apache.log4j.Logger;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.FactoryBean;

/**
 * 创建分布式锁模板实例的工厂Bean
 *
 * @author lk
 */
public class DistributedLockFactoryBean implements FactoryBean<DistributedLockTemplate> {
    private Logger                  logger = Logger.getLogger(DistributedLockFactoryBean.class);

    private LockInstanceMode        mode;

    private DistributedLockTemplate distributedLockTemplate;

    private RedissonClient redisson;

    @PostConstruct
    public void init() {
        String ip = "127.0.0.1";
        String port = "6379";
        Config config=new Config();
        config.useSingleServer().setAddress(ip+":"+port);
        redisson=Redisson.create(config);
        System.out.println("成功连接Redis Server"+"\t"+"连接"+ip+":"+port+"服务器");
    }

    @PreDestroy
    public void destroy() {
        logger.debug("销毁分布式锁模板");
        redisson.shutdown();
    }

    @Override
    public DistributedLockTemplate getObject() throws Exception {
        switch (mode) {
            case SINGLE:
                distributedLockTemplate = new SingleDistributedLockTemplate(redisson);
                break;
        }
        return distributedLockTemplate;
    }

    @Override
    public Class<?> getObjectType() {
        return DistributedLockTemplate.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

    public void setMode(String mode) {
        if (mode==null||mode.length()<=0||mode.equals("")) {
            throw new IllegalArgumentException("未找到dlm.redisson.mode配置项");
        }
        this.mode = LockInstanceMode.parse(mode);
        if (this.mode == null) {
            throw new IllegalArgumentException("不支持的分布式锁模式");
        }
    }

    private enum LockInstanceMode {
        SINGLE;
        public static LockInstanceMode parse(String name) {
            for (LockInstanceMode modeIns : LockInstanceMode.values()) {
                if (modeIns.name().equals(name.toUpperCase())) {
                    return modeIns;
                }
            }
            return null;
        }
    }
}

 配置进spring boot中

package com.example.demo.redis2;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Created by LiaoKe on 2017/5/22.
 */
@Configuration
public class BeanConfig {

    @Bean
    public DistributedLockFactoryBean distributeLockTemplate(){
        DistributedLockFactoryBean d  = new DistributedLockFactoryBean();
        d.setMode("SINGLE");
        return d;
    }
}

 

目前为止已经可以使用。

为了验证锁是否成功,我做了如下例子。

首先建立了一个数据库实体(使用的JPA),模拟被购买的商品数量,当被购买后,num+1

在高并发环境下,这必定会有问题,因为在查询之后的设值,存在对同一数据库源的操作。

 

package com.example.demo.redis2.entity;

import org.hibernate.annotations.GenericGenerator;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

/**
 * 测试类实体
 * Created by LiaoKe on 2017/5/22.
 */
@Entity
public class TestEntity {
    @Id
    @GeneratedValue(generator = "system-uuid")
    @GenericGenerator(name = "system-uuid", strategy = "uuid")
    private String id;
    private Integer num;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public Integer getNum() {
        return num;
    }

    public void setNum(Integer num) {
        this.num = num;
    }
}

 

 

具体数据库操作,加锁和不加锁的操作,要注意我使用了@Async,异步任务注解,我没有配置线程池信息,使用的默认线程池。

package com.example.demo.redis2.service;

import com.example.demo.redis2.DistributedLockCallback;
import com.example.demo.redis2.DistributedLockTemplate;
import com.example.demo.redis2.dao.TestEntityRepository;
import com.example.demo.redis2.entity.TestEntity;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * Created by LiaoKe on 2017/5/22.
 */
@Service
public class AsyncService {

    @Resource
    TestEntityRepository ts;


    @Resource
    DistributedLockTemplate distributedLockTemplate;

    /**
     * 加锁
     */
    @Async
    public void addAsync(){
        distributedLockTemplate.lock(new DistributedLockCallback<Object>(){
            @Override
            public Object process() {
                add();
                return null;
            }

            @Override
            public String getLockName() {
                return "MyLock";
            }
        });
    }

    /**
     * 未加锁
     */
    @Async
    public void addNoAsync(){
        add();
    }

    /**
     * 测试异步方法
     * 在不加分布式锁的情况下
     * num数目会混乱
     */
    @Async
    private void add(){
        if(ts.findAll().size()==0){
            TestEntity  t  =  new TestEntity();
            t.setNum(1);
            ts.saveAndFlush(t);
        }else{
            TestEntity dbt = ts.findAll().get(0);
            dbt.setNum(dbt.getNum()+1);
            ts.saveAndFlush(dbt);
        }
    }


}

 

最后为了测试简单跑了两个接口

package com.example.demo;

import com.example.demo.redis2.DistributedLockTemplate;
import com.example.demo.redis2.service.AsyncService;
import oracle.jrockit.jfr.StringConstantPool;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

@SpringBootApplication
@RestController
@EnableAsync
public class DemoApplication {

	public static void main(String[] args) {
		SpringApplication.run(DemoApplication.class, args);
	}


	@Resource
	AsyncService as;


	@GetMapping("")
	public void test(){
		for(int i = 0 ;i<10000;i++){
			as.addNoAsync();
		}
	}

	@GetMapping("lock")
	public void  test2(){
		for(int i = 0 ;i<10000;i++){
			as.addAsync();
		}
	}
}

 

 访问localhost:8888 及 localhost:8888/lock

在不加锁的情况下



 数据库已经爆炸了

最后得到的数据奇奇怪怪



 

使用加锁后的访问



 可以看到库存增加绝对正确。

此处并未使用任何数据库锁,并且基于redis,可在不同的网络节点实现上锁。

 

这只是简单的实现,在真正的生产环境中,还要注意许多问题,超时和放锁时机需要好好研究,在此不便贴真正项目代码。

 

参考博客:http://layznet.iteye.com/blog/2307179   感谢作者

  • 大小: 3.6 KB
  • 大小: 5.4 KB
  • 大小: 4.1 KB
分享到:
评论
1 楼 CodeMonkey_Xiong 2017-05-22  
博主大人威武!!!  

相关推荐

    记录redisson实现redis分布式事务锁

    本篇文章将详细探讨如何使用Redisson实现Redis分布式事务锁,以及在Spring Boot环境中如何进行集成。 首先,Redis作为一个内存数据库,其高速读写性能使其成为实现分布式锁的理想选择。分布式锁的主要作用是在多...

    spring boot 利用redisson实现redis的分布式锁(二)

    NULL 博文链接:https://liaoke0123.iteye.com/blog/2375556

    springboot基于redis分布式锁

    3. **简单的API**:Redis提供了丰富的命令集,如`SETNX`、`EXPIRE`等,方便实现锁的逻辑。 要在SpringBoot中集成Redis,你需要先在项目中添加对应的依赖。SpringBoot提供了对Redis的自动配置支持,只需在`pom.xml`...

    java开发基于SpringBoot+WebSocket+Redis分布式即时通讯群聊系统.zip

    Java开发基于SpringBoot+WebSocket+Redis分布式即时通讯群聊系统。一个基于Spring Boot + WebSocket + Redis,可快速开发的分布式即时通讯群聊系统。适用于直播间聊天、游戏内聊天、客服聊天等临时性群聊场景。 ...

    案例实战-SpringBoot整合Redisson实现RedLock分布式锁同步

    RedLock是Redisson中的一个特性,它由Redis社区提出,旨在提供一种更健壮的分布式锁实现,比单节点Redis的`setnx`命令更可靠。 RedLock的实现基于以下假设: 1. 时钟偏移:所有参与的Redis服务器的时钟大致同步。 2...

    Spring Boot+Redis 分布式锁:模拟抢单.docx

    Spring Boot+Redis 分布式锁:模拟抢单

    Spring Boot+Redis 分布式锁:模拟抢单.pdf

    本次文档将围绕Spring Boot结合Redis实现分布式锁的机制进行详细解读,并通过模拟抢单的场景来展示其实际运用。 首先,了解Redis的分布式锁是如何运作的至关重要。在Redis的诸多操作中,`set`命令的`nx`选项(即`...

    Spring Boot Redis 实现分布式锁的方法详解.docx

    本篇文章将详细讲解如何利用 Spring Boot 结合 Redis 实现分布式锁。 首先,理解分布式锁的基本概念。分布式锁是在分布式系统中用于控制并发访问的机制,它允许只有一台机器或一个线程在任何时候持有锁,从而确保对...

    基于Spring Boot框架的分布式锁服务.zip

    Redis分布式锁利用Redis的SETNX命令实现分布式锁,确保在分布式环境下对资源的互斥访问。 Redisson分布式锁使用Redisson库提供的分布式锁实现,提供更高级的功能,如锁的自动续期和可重入锁。 2. 锁的续期和释放...

    redis实现全局锁 Redisson的Spring Boot核心 RedissonLock.zip

    redis实现全局锁 Redisson的Spring Boot核心 RedissonLockRedisson实现分布式锁有关Redisson实现环球锁前面写了三篇博客该项目作为项目落地的铺垫。1、Redisson实现全局锁(1)---原理2、Redisson实现全球锁(2)——...

    基于Spring Boot + WebSocket + Redis,可快速开发的分布式即时通讯群聊系统.zip

    基于Spring Boot + WebSocket + Redis,可快速开发的分布式即时通讯群聊系统.zip 1、该资源内项目代码经过严格调试,下载即用确保可以运行! 2、该资源适合计算机相关专业(如计科、人工智能、大数据、数学、电子信息...

    spring-boot-redis-token 分布式锁 redis session

    http://localhost:8080/ass/getUser 测试是否登录 http://localhost:8080/any/user/passLogin 登录测试 http://localhost:8080/lock redis分布式锁测试

    redis分布式锁工具包提供纯Java方式调用

    7. **Spring Boot Starter**:对于Spring Boot应用,工具包提供的Starter可以通过简单的配置,自动将Redis分布式锁集成到应用中,减少手动配置的工作量。 在使用这个工具包时,开发者需要注意以下几点: - **正确...

    redis分布式锁,解决死锁问题

    项目为spring boot实现,maven生成jar包能直接运行 ...三种方式实现redis分布式锁 1.redis incr计数器实现 2.redis setIfAbsent 3.redisson 博客:https://blog.csdn.net/u011974797/article/details/81238079

    spring-boot-distributed-redisson:redis实现分布式锁 Spring Boot core for Redisson RedissonLock

    Redisson实现分布式锁 有关Redisson实现分布式锁前面写了三篇博客作为该项目落地的铺垫。 1、 2、 3、 该项目可以直接运用于实际开发中,作为分布式锁使用。 一、项目概述 1、技术架构 项目总体技术选型 SpringBoot...

    (源码)基于Spring Boot和Redis的分布式系统.zip

    项目涵盖了从基础的Spring Boot应用配置到高级的分布式锁、缓存管理、消息队列等功能的实现。 ## 项目的主要特性和功能 ### 1. Spring Boot基础配置 Spring Boot应用启动类通过SpringBootApplication注解快速...

    Spring boot整合分布式缓存Redis

    通过这些配置,Spring Boot应用可以利用Redisson提供的高级特性,例如分布式锁和原子数等,来解决分布式系统中的并发问题和资源同步问题。 另外,整合后的Spring Boot应用能够轻松地通过注解方式,例如@...

    SpringBoot 使用 Redis 分布式锁解决并发问题.docx

    在SpringBoot应用中集成Redis分布式锁,可以创建一个`RedisLock`工具类,包含加锁和解锁的方法。加锁操作需要确保原子性,即同时设置键和过期时间,这在SpringBoot 2.x版本以上可以通过`opsForValue().setIfAbsent()...

    基于Spring Boot的Redisson集成与扩展设计源码

    深度集成意味着开发者可以将Redisson的功能无缝地融入Spring Boot应用中,从而使应用能够充分利用Redisson提供的各种数据结构和分布式服务。在企业级应用开发中,这种集成能够大幅度提升应用的性能和扩展性。 其次...

Global site tag (gtag.js) - Google Analytics