spring boot 利用redisson实现redis的分布式锁
原文:http://liaoke0123.iteye.com/blog/2375469
利用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 感谢作者
spring boot 利用redisson实现redis的分布式锁的更多相关文章
- 利用多写Redis实现分布式锁原理与实现分析(转)
利用多写Redis实现分布式锁原理与实现分析 一.关于分布式锁 关于分布式锁,可能绝大部分人都会或多或少涉及到. 我举二个例子:场景一:从前端界面发起一笔支付请求,如果前端没有做防重处理,那么可能 ...
- 利用consul在spring boot中实现最简单的分布式锁
因为在项目实际过程中所采用的是微服务架构,考虑到承载量基本每个相同业务的服务都是多节点部署,所以针对某些资源的访问就不得不用到用到分布式锁了. 这里列举一个最简单的场景,假如有一个智能售货机,由于机器 ...
- 基于redis的分布式锁实现方案--redisson
实例代码地址,请前往:https://gitee.com/GuoqingLee/distributed-seckill redis官方文档地址,请前往:http://www.redis.cn/topi ...
- Spring Boot Redis 实现分布式锁,真香!!
之前看很多人手写分布式锁,其实 Spring Boot 现在已经做的足够好了,开箱即用,支持主流的 Redis.Zookeeper 中间件,另外还支持 JDBC. 本篇栈长以 Redis 为例(这也是 ...
- 来吧,展示!Redis的分布式锁及其实现Redisson的全过程
前言 分布式锁是控制分布式系统之间同步访问共享资源的一种方式. 在分布式系统中,常常需要协调他们的动作.如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要 ...
- Spring Boot 2.x整合Redis
最近在学习Spring Boot 2.x整合Redis,在这里和大家分享一下,希望对大家有帮助. Redis是什么 Redis 是开源免费高性能的key-value数据库.有以下的优势(源于Redis ...
- 利用redis实现分布式锁知识点总结及相关改进
利用redis实现分布式锁知识点总结及相关改进 先上原文,本文只为总结及对相关内容的质疑并提出若干意见,原文内容更详细https://www.cnblogs.com/linjiqin/p/800383 ...
- Spring Boot 利用 nginx 实现生产环境的伪热更新
当我们在服务器部署Java程序,特别是使用了 Spring Boot 生成单一 Jar 文件部署的时候,单一文件为我们开发单来的极大的便利性,保障程序的完整性.但同时对我们修改程序中的任何一处都带来重 ...
- 通过Redis 实现分布式锁_利用Jedis 客户端
前言 分布式锁一般有三种实现方式: 数据库乐观锁:2. 基于Redis的分布式锁:3. 基于ZooKeeper的分布式锁. 本篇博客将介绍第二种方式,基于Redis实现分布式锁. 虽然网上已经有各种介 ...
随机推荐
- Java中volatile修饰符,不稳定标记的用法笔记
今天学java特性时,发现了volatile修饰符,这个修饰符修饰的变量告诉java编译器忽略优化机制,这样的优势是: java优化后,寄存器会缓存内存里的变量,另一个线程修改这个变量的内存时,不会同 ...
- 辨别苹果数据线真伪 苹果计算器 Dashboard 知识
辨别苹果数据线真伪 苹果计算器 Dashboard 知识 苹果数据线真伪的最简单的辨别: 线质柔软 用数据线连接适配器(苹果自带的适配器)充电 连接手机 如果该手机数据线是假的, 在手机上会提示”该 ...
- python_基于反射模拟Web框架路由系统
根据用户输入的内容,导入模块 #根据用户输入的内容,导入模块 inp = input("请输入模块名: ") print(inp,type(inp)) dd = __import_ ...
- Spring + MyBatis 多数据源实现
近期,在项目中需要做分库,但是因为某些原因,没有采用开源的分库插件,而是采用了同事之前弄得多数据源形式实现的分库.对于多数据源,本人在实际项目也中遇到的不多,之前的项目大多是服务化,以RPC的形式获得 ...
- rabbitmq源码安装及配置文件管理
rabbitmq 源码安装 官网地址:rabbitmq http://www.rabbitmq.com/releases/rabbitmq-server/ 官网地址:erlang http://erl ...
- 基于flask和百度AI接口实现前后端的语音交互
话不多说,直接怼代码,有不懂的,可以留言 简单的实现,前后端的语音交互. import os from uuid import uuid4 from aip import AipSpeech from ...
- WordPress函数query_posts用法汇总
最近经常有网友跟我咨询WordPress函数query_posts的相关用法,说起来query_posts实在是太强大,参数无数,用法更是无数,如果让我说它的用法,我根本没法一一说清楚.开始之前,你可 ...
- 前端读者 | 前端构建工具Gulp
@羯瑞 整理 前言 前端工具现在层出不穷,网上搜下一大片,就看你怎么去使用了,基于项目看用什么样的构建工具.有的工具提供的功能还是非常强大的. FIS.百度团队的产品.现在百度的多个产品中使用.面向前 ...
- 基于node的前端页面实时更新。呦吼~
学习了gulp,webpack后越发觉得前端开发万分的有趣,首当其冲的就是解决了狂按f5的尴尬. 当我们按下ctrl+s保存后页面自动更新了,我就觉得我f5键在隐隐的发笑. 1.node_npm_li ...
- DOM方法index()相关问题(为何$(this).index(this)是错误的 )
写jQuery的时候遇到一个关于index()的问题,查找相关资料后,解决了,把自己的想法写在下面. index() 方法返回指定元素相对于其他指定元素的 index 位置. 完全语法为:$(sele ...