1.  Redisson

Redisson是Redis官方推荐的Java版的Redis客户端。它提供的功能非常多,也非常强大,此处我们只用它的分布式锁功能。

https://github.com/redisson/redisson

1.1.  基本用法

1 <dependency>
2 <groupId>org.redisson</groupId>
3 <artifactId>redisson</artifactId>
4 <version>3.11.1</version>
5 </dependency>

1.2.  Distributed locks and synchronizers

RedissonClient中提供了好多种锁,还有其它很多实用的方法

1.2.1.  Lock

默认,非公平锁

最简洁的一种方法

指定超时时间

异步

1.2.2  Fair Lock

1.2.3  MultiLock

1.2.4  RedLock

1.3.  示例

pom.xml

 1 <?xml version="1.0" encoding="UTF-8"?>
2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4 <modelVersion>4.0.0</modelVersion>
5 <parent>
6 <groupId>org.springframework.boot</groupId>
7 <artifactId>spring-boot-starter-parent</artifactId>
8 <version>2.1.6.RELEASE</version>
9 <relativePath/> <!-- lookup parent from repository -->
10 </parent>
11 <groupId>com.cjs.example</groupId>
12 <artifactId>cjs-redisson-example</artifactId>
13 <version>0.0.1-SNAPSHOT</version>
14 <name>cjs-redisson-example</name>
15
16 <properties>
17 <java.version>1.8</java.version>
18 </properties>
19
20 <dependencies>
21 <dependency>
22 <groupId>org.springframework.boot</groupId>
23 <artifactId>spring-boot-starter-data-jpa</artifactId>
24 </dependency>
25 <dependency>
26 <groupId>org.springframework.boot</groupId>
27 <artifactId>spring-boot-starter-data-redis</artifactId>
28 </dependency>
29 <dependency>
30 <groupId>org.springframework.boot</groupId>
31 <artifactId>spring-boot-starter-web</artifactId>
32 </dependency>
33
34 <!-- https://github.com/redisson/redisson#quick-start -->
35 <dependency>
36 <groupId>org.redisson</groupId>
37 <artifactId>redisson</artifactId>
38 <version>3.11.1</version>
39 </dependency>
40
41
42 <dependency>
43 <groupId>org.apache.commons</groupId>
44 <artifactId>commons-lang3</artifactId>
45 <version>3.9</version>
46 </dependency>
47 <dependency>
48 <groupId>com.alibaba</groupId>
49 <artifactId>fastjson</artifactId>
50 <version>1.2.58</version>
51 </dependency>
52 <dependency>
53 <groupId>org.apache.commons</groupId>
54 <artifactId>commons-pool2</artifactId>
55 <version>2.6.2</version>
56 </dependency>
57
58 <dependency>
59 <groupId>mysql</groupId>
60 <artifactId>mysql-connector-java</artifactId>
61 <scope>runtime</scope>
62 </dependency>
63 <dependency>
64 <groupId>org.projectlombok</groupId>
65 <artifactId>lombok</artifactId>
66 <optional>true</optional>
67 </dependency>
68 </dependencies>
69
70 <build>
71 <plugins>
72 <plugin>
73 <groupId>org.springframework.boot</groupId>
74 <artifactId>spring-boot-maven-plugin</artifactId>
75 </plugin>
76 </plugins>
77 </build>
78
79 </project>

application.yml

 1 server:
2 port:
3 spring:
4 application:
5 name: cjs-redisson-example
6 redis:
7 cluster:
8 nodes: 10.0.29.30:, 10.0.29.95:, 10.0.29.205:
9 lettuce:
10 pool:
11 min-idle:
12 max-idle:
13 max-active:
14 datasource:
15 url: jdbc:mysql://127.0.0.1:3306/test
16 username: root
17 password:
18 driver-class-name: com.mysql.cj.jdbc.Driver
19 type: com.zaxxer.hikari.HikariDataSource

RedissonConfig.java

 1 package com.cjs.example.lock.config;
2
3 import org.redisson.Redisson;
4 import org.redisson.api.RedissonClient;
5 import org.redisson.config.Config;
6 import org.springframework.context.annotation.Bean;
7 import org.springframework.context.annotation.Configuration;
8
9 /**
10 * @author ChengJianSheng
11 * @date 2019-07-26
12 */
13 @Configuration
14 public class RedissonConfig {
15
16 @Bean
17 public RedissonClient redissonClient() {
18 Config config = new Config();
19 config.useClusterServers()
20 .setScanInterval()
21 .addNodeAddress("redis://10.0.29.30:6379", "redis://10.0.29.95:6379")
22 .addNodeAddress("redis://10.0.29.205:6379");
23
24 RedissonClient redisson = Redisson.create(config);
25
26 return redisson;
27 }
28
29 }

CourseServiceImpl.java

  1 package com.cjs.example.lock.service.impl;
2
3 import com.alibaba.fastjson.JSON;
4 import com.cjs.example.lock.constant.RedisKeyPrefixConstant;
5 import com.cjs.example.lock.model.CourseModel;
6 import com.cjs.example.lock.model.CourseRecordModel;
7 import com.cjs.example.lock.repository.CourseRecordRepository;
8 import com.cjs.example.lock.repository.CourseRepository;
9 import com.cjs.example.lock.service.CourseService;
10 import lombok.extern.slf4j.Slf4j;
11 import org.apache.commons.lang3.StringUtils;
12 import org.redisson.api.RLock;
13 import org.redisson.api.RedissonClient;
14 import org.springframework.beans.factory.annotation.Autowired;
15 import org.springframework.data.redis.core.HashOperations;
16 import org.springframework.data.redis.core.StringRedisTemplate;
17 import org.springframework.stereotype.Service;
18
19 import java.util.concurrent.TimeUnit;
20
21 /**
22 * @author ChengJianSheng
23 * @date 2019-07-26
24 */
25 @Slf4j
26 @Service
27 public class CourseServiceImpl implements CourseService {
28
29 @Autowired
30 private CourseRepository courseRepository;
31 @Autowired
32 private CourseRecordRepository courseRecordRepository;
33 @Autowired
34 private StringRedisTemplate stringRedisTemplate;
35 @Autowired
36 private RedissonClient redissonClient;
37
38 @Override
39 public CourseModel getById(Integer courseId) {
40
41 CourseModel courseModel = null;
42
43 HashOperations<String, String, String> hashOperations = stringRedisTemplate.opsForHash();
44
45 String value = hashOperations.get(RedisKeyPrefixConstant.COURSE, String.valueOf(courseId));
46
47 if (StringUtils.isBlank(value)) {
48 String lockKey = RedisKeyPrefixConstant.LOCK_COURSE + courseId;
49 RLock lock = redissonClient.getLock(lockKey);
50 try {
51 boolean res = lock.tryLock(, TimeUnit.SECONDS);
52 if (res) {
53 value = hashOperations.get(RedisKeyPrefixConstant.COURSE, String.valueOf(courseId));
54 if (StringUtils.isBlank(value)) {
55 log.info("从数据库中读取");
56 courseModel = courseRepository.findById(courseId).orElse(null);
57 hashOperations.put(RedisKeyPrefixConstant.COURSE, String.valueOf(courseId), JSON.toJSONString(courseModel));
58 }
59 }
60 } catch (InterruptedException e) {
61 e.printStackTrace();
62 } finally {
63 lock.unlock();
64 }
65 } else {
66 log.info("从缓存中读取");
67 courseModel = JSON.parseObject(value, CourseModel.class);
68 }
69
70 return courseModel;
71 }
72
73 @Override
74 public void upload(Integer userId, Integer courseId, Integer studyProcess) {
75
76 HashOperations<String, String, String> hashOperations = stringRedisTemplate.opsForHash();
77
78 String cacheKey = RedisKeyPrefixConstant.COURSE_PROGRESS + ":" + userId;
79 String cacheValue = hashOperations.get(cacheKey, String.valueOf(courseId));
80 if (StringUtils.isNotBlank(cacheValue) && studyProcess <= Integer.valueOf(cacheValue)) {
81 return;
82 }
83
84 String lockKey = "upload:" + userId + ":" + courseId;
85
86 RLock lock = redissonClient.getLock(lockKey);
87
88 try {
89 lock.lock(, TimeUnit.SECONDS);
90
91 cacheValue = hashOperations.get(cacheKey, String.valueOf(courseId));
92 if (StringUtils.isBlank(cacheValue) || studyProcess > Integer.valueOf(cacheValue)) {
93 CourseRecordModel model = new CourseRecordModel();
94 model.setUserId(userId);
95 model.setCourseId(courseId);
96 model.setStudyProcess(studyProcess);
97 courseRecordRepository.save(model);
98 hashOperations.put(cacheKey, String.valueOf(courseId), String.valueOf(studyProcess));
99 }
100
101 } catch (Exception ex) {
102 log.error("获取所超时!", ex);
103 } finally {
104 lock.unlock();
105 }
106
107 }
108 }

StockServiceImpl.java

 1 package com.cjs.example.lock.service.impl;
2
3 import com.cjs.example.lock.constant.RedisKeyPrefixConstant;
4 import com.cjs.example.lock.service.StockService;
5 import org.apache.commons.lang3.StringUtils;
6 import org.springframework.beans.factory.annotation.Autowired;
7 import org.springframework.data.redis.core.HashOperations;
8 import org.springframework.data.redis.core.StringRedisTemplate;
9 import org.springframework.stereotype.Service;
10
11 /**
12 * @author ChengJianSheng
13 * @date 2019-07-26
14 */
15 @Service
16 public class StockServiceImpl implements StockService {
17
18 @Autowired
19 private StringRedisTemplate stringRedisTemplate;
20
21 @Override
22 public int getByProduct(Integer productId) {
23 HashOperations<String, String, String> hashOperations = stringRedisTemplate.opsForHash();
24 String value = hashOperations.get(RedisKeyPrefixConstant.STOCK, String.valueOf(productId));
25 if (StringUtils.isBlank(value)) {
26 return ;
27 }
28 return Integer.valueOf(value);
29 }
30
31 @Override
32 public boolean decrease(Integer productId) {
33 int stock = getByProduct(productId);
34 if (stock <= ) {
35 return false;
36 }
37 HashOperations<String, String, String> hashOperations = stringRedisTemplate.opsForHash();
38 hashOperations.put(RedisKeyPrefixConstant.STOCK, String.valueOf(productId), String.valueOf(stock - ));
39 return true;
40 }
41 }

OrderServiceImpl.java

 1 package com.cjs.example.lock.service.impl;
2
3 import com.cjs.example.lock.model.OrderModel;
4 import com.cjs.example.lock.repository.OrderRepository;
5 import com.cjs.example.lock.service.OrderService;
6 import com.cjs.example.lock.service.StockService;
7 import lombok.extern.slf4j.Slf4j;
8 import org.redisson.api.RLock;
9 import org.redisson.api.RedissonClient;
10 import org.springframework.beans.factory.annotation.Autowired;
11 import org.springframework.stereotype.Service;
12
13 import java.util.Date;
14 import java.util.UUID;
15 import java.util.concurrent.TimeUnit;
16
17 /**
18 * @author ChengJianSheng
19 * @date 2019-07-30
20 */
21 @Slf4j
22 @Service
23 public class OrderServiceImpl implements OrderService {
24
25 @Autowired
26 private StockService stockService;
27 @Autowired
28 private OrderRepository orderRepository;
29 @Autowired
30 private RedissonClient redissonClient;
31
32 /**
33 * 乐观锁
34 */
35 @Override
36 public String save(Integer userId, Integer productId) {
37 int stock = stockService.getByProduct(productId);
38 log.info("剩余库存:{}", stock);
39 if (stock <= ) {
40 return null;
41 }
42
43 // 如果不加锁,必然超卖
44
45 RLock lock = redissonClient.getLock("stock:" + productId);
46
47 try {
48 lock.lock(, TimeUnit.SECONDS);
49
50 String orderNo = UUID.randomUUID().toString().replace("-", "").toUpperCase();
51
52 if (stockService.decrease(productId)) {
53
54 OrderModel orderModel = new OrderModel();
55 orderModel.setUserId(userId);
56 orderModel.setProductId(productId);
57 orderModel.setOrderNo(orderNo);
58 Date now = new Date();
59 orderModel.setCreateTime(now);
60 orderModel.setUpdateTime(now);
61 orderRepository.save(orderModel);
62
63 return orderNo;
64 }
65
66 } catch (Exception ex) {
67 log.error("下单失败", ex);
68 } finally {
69 lock.unlock();
70 }
71
72 return null;
73 }
74
75 }

OrderModel.java

 1 package com.cjs.example.lock.model;
2
3 import lombok.Data;
4
5 import javax.persistence.*;
6 import java.io.Serializable;
7 import java.util.Date;
8
9 /**
10 * @author ChengJianSheng
11 * @date 2019-07-30
12 */
13 @Data
14 @Entity
15 @Table(name = "t_order")
16 public class OrderModel implements Serializable {
17
18 @Id
19 @GeneratedValue(strategy = GenerationType.IDENTITY)
20 private Integer id;
21
22 @Column(name = "order_no")
23 private String orderNo;
24
25 @Column(name = "product_id")
26 private Integer productId;
27
28 @Column(name = "user_id")
29 private Integer userId;
30
31 @Column(name = "create_time")
32 private Date createTime;
33
34 @Column(name = "update_time")
35 private Date updateTime;
36 } 

数据库脚本.sql

 1 SET NAMES utf8mb4;
2 SET FOREIGN_KEY_CHECKS = ;
3
4 -- ----------------------------
5 -- Table structure for t_course
6 -- ----------------------------
7 DROP TABLE IF EXISTS `t_course`;
8 CREATE TABLE `t_course` (
9 `id` int() NOT NULL AUTO_INCREMENT,
10 `course_name` varchar() NOT NULL,
11 `course_type` tinyint() NOT NULL DEFAULT '1',
12 `start_time` datetime NOT NULL,
13 PRIMARY KEY (`id`)
14 ) ENGINE=InnoDB AUTO_INCREMENT= DEFAULT CHARSET=utf8mb4;
15
16 -- ----------------------------
17 -- Table structure for t_order
18 -- ----------------------------
19 DROP TABLE IF EXISTS `t_order`;
20 CREATE TABLE `t_order` (
21 `id` int() NOT NULL AUTO_INCREMENT,
22 `order_no` varchar() CHARACTER SET latin1 NOT NULL,
23 `user_id` int() NOT NULL,
24 `product_id` int() NOT NULL,
25 `create_time` datetime NOT NULL,
26 `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
27 PRIMARY KEY (`id`)
28 ) ENGINE=InnoDB AUTO_INCREMENT= DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
29
30 -- ----------------------------
31 -- Table structure for t_user_course_record
32 -- ----------------------------
33 DROP TABLE IF EXISTS `t_user_course_record`;
34 CREATE TABLE `t_user_course_record` (
35 `id` int() NOT NULL AUTO_INCREMENT,
36 `user_id` int() NOT NULL,
37 `course_id` int() NOT NULL,
38 `study_process` int() NOT NULL,
39 PRIMARY KEY (`id`)
40 ) ENGINE=InnoDB AUTO_INCREMENT= DEFAULT CHARSET=utf8mb4;
41
42 SET FOREIGN_KEY_CHECKS = ; 

1.4  工程结构

https://github.com/chengjiansheng/cjs-redisson-example

1.5  Redis集群创建

1.6  测试

测试/course/upload

测试/order/create

2.  Spring Integration

用法与Redisson类似

1 <dependency>
2 <groupId>org.springframework.boot</groupId>
3 <artifactId>spring-boot-starter-integration</artifactId>
4 </dependency>
5 <dependency>
6 <groupId>org.springframework.integration</groupId>
7 <artifactId>spring-integration-redis</artifactId>
8 </dependency>
 1 package com.kaishustory.base.conf;
2
3 import org.springframework.context.annotation.Bean;
4 import org.springframework.context.annotation.Configuration;
5 import org.springframework.data.redis.connection.RedisConnectionFactory;
6 import org.springframework.integration.redis.util.RedisLockRegistry;
7
8 /**
9 * @author ChengJianSheng
10 * @date 2019-07-30
11 */
12 @Configuration
13 public class RedisLockConfig {
14
15 @Bean
16 public RedisLockRegistry redisLockRegistry(RedisConnectionFactory redisConnectionFactory) {
17 return new RedisLockRegistry(redisConnectionFactory, "asdf")
18 }
19
20 }
 1 @Autowired
2 private RedisLockRegistry redisLockRegistry;
3
4 public void save(Integer userId) {
5
6 String lockKey = "order:" + userId;
7
8 Lock lock = redisLockRegistry.obtain(lockKey);
9 try {
10 lock.lock();
11
12 //todo
13
14 } finally {
15 lock.unlock();
16 }
17
18 }

3.  其它

https://github.com/redisson/redisson/wiki/8.-Distributed-locks-and-synchronizers

https://www.cnblogs.com/cjsblog/p/9831423.html

Redisson基本用法的更多相关文章

  1. 关于为了一时方便,使用@Scheduled注解定时踩的坑

    摘要: 事情是这样的前两周在做项目的时候碰到一个需求---要求每天晚上执行一个任务,公司统一使用的是 xxl-job 写定时任务的,我当时为了方便自己,然后就简单的使用了Spring的那个@Sched ...

  2. Java使用Redisson分布式锁实现原理

    本篇文章摘自:https://www.jb51.net/article/149353.htm 由于时间有限,暂未验证 仅先做记录.有大家注意下哈(会尽快抽时间进行验证) 1. 基本用法 添加依赖 &l ...

  3. 使用Redisson实现分布式锁

    原文:https://www.jianshu.com/p/cde0700f0128 1. 可重入锁(Reentrant Lock) Redisson的分布式可重入锁RLock Java对象实现了jav ...

  4. Java之——redis并发读写锁,使用Redisson实现分布式锁

    原文:http://blog.csdn.net/l1028386804/article/details/73523810 1. 可重入锁(Reentrant Lock) Redisson的分布式可重入 ...

  5. 【连载】redis库存操作,分布式锁的四种实现方式[二]--基于Redisson实现分布式锁

    一.redisson介绍 redisson实现了分布式和可扩展的java数据结构,支持的数据结构有:List, Set, Map, Queue, SortedSet, ConcureentMap, L ...

  6. 使用Apache,压力测试redisson的一般高并发

    安装 Linux linux直接yum -y install httpd-tools,然后ab -V测试 Windows 1查看80端口有没有被占用,netstat -ano | findstr &q ...

  7. 【高并发】你知道吗?大家都在使用Redisson实现分布式锁了!!

    写在前面 忘记之前在哪个群里有朋友在问:有出分布式锁的文章吗-@冰河?我的回答是:这周会有,也是[高并发]专题的.想了想,还是先发一个如何使用Redisson实现分布式锁的文章吧?为啥?因为使用Red ...

  8. 又长又细,万字长文带你解读Redisson分布式锁的源码

    前言 上一篇文章写了Redis分布式锁的原理和缺陷,觉得有些不过瘾,只是简单的介绍了下Redisson这个框架,具体的原理什么的还没说过呢.趁年前项目忙的差不多了,反正闲着也是闲着,不如把Rediss ...

  9. 分布式锁中的王者方案-Redisson

    上篇讲解了如何用 Redis 实现分布式锁的五种方案,但我们还是有更优的王者方案,就是用 Redisson. 缓存系列文章: 缓存实战(一):20 图 |6 千字|缓存实战(上篇) 缓存实战(二):R ...

随机推荐

  1. 关于OV7670摄像头的分辨率设置

    关于OV7670摄像头的分辨率设置最近一直在纠结如何把OV7670输出的图片分辨率缩小,以减少数据量来适应数据的传输,在网上看了好多也没有关于寄存器的具体设置,最终又读了几遍数据手册,加上网友们写的帖 ...

  2. HTTP请求流程你了解了么?

    我又回来了,先来波推广,最硬的资源来自公众号:前端美食汇,欢迎大家关注公众号获取最新的技术.提示,文末有福利,最硬的文章会首先发布在公众号上喔 预备知识 前文没有描述到传输和协议直接的层级对应关系,大 ...

  3. margin重叠与穿透问题

    margin重叠是指两个同级元素之间.margin穿透指的是,子元素margin超出父元素而未被父元素包含的现象. 出现margin重叠的原因: 同一个BFC里面两个块级元素会出现margin折叠. ...

  4. Python流程控制之循环结构

    目录 while循环 for循环 嵌套循环 break.continue.pass 练习 当出现有规律或者是重复的事情就可以使用循环. 1.循环变量初始化 2.循环条件 3.循环体 4.改变循环变量 ...

  5. 【Java Web开发学习】Spring MVC 拦截器HandlerInterceptor

    [Java Web开发学习]Spring MVC 拦截器HandlerInterceptor 转载:https://www.cnblogs.com/yangchongxing/p/9324119.ht ...

  6. pv操作与信号量详解

    对于信号量,可以认为是一个仓库,有两个概念,容量和当前的货物个数. P操作从仓库拿货,如果仓库中没有货,线程一直等待,直到V操作,往仓库里添加了货物,为了避免P操作一直等待下去,会有一个超时时间. V ...

  7. 高仿 django插拔式 及 settings配置文件

    目录 基于django中间件实现插拔式 仿django settings 基于django中间件实现插拔式 start.py from notify import * send_all('好嗨哦') ...

  8. 如何用Jmeter做接口测试

    Jmeter介绍&测试准备: Jmeter介绍:Jmeter是软件行业里面比较常用的接口.性能测试工具,下面介绍下如何用Jmeter做接口测试以及如何用它连接MySQL数据库. 前期准备:测试 ...

  9. CodeForces - 556C Case of Matryoshkas (水题)

    Andrewid the Android is a galaxy-famous detective. He is now investigating the case of vandalism at ...

  10. 【程序人生】一个IT人的立功,立言,立德三不朽

    最近几个月很忙,忙着当奶爸,忙着做加班狗,忙着补裤裆学技术……以至于快忘了要思考人生了! 古人立志穷极一生追求“立德”,“立功”,“立言”,以求不朽,为万世所景仰,为后人所传颂,实现人生的意义.立德者 ...