Redisson基本用法
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基本用法的更多相关文章
- 关于为了一时方便,使用@Scheduled注解定时踩的坑
摘要: 事情是这样的前两周在做项目的时候碰到一个需求---要求每天晚上执行一个任务,公司统一使用的是 xxl-job 写定时任务的,我当时为了方便自己,然后就简单的使用了Spring的那个@Sched ...
- Java使用Redisson分布式锁实现原理
本篇文章摘自:https://www.jb51.net/article/149353.htm 由于时间有限,暂未验证 仅先做记录.有大家注意下哈(会尽快抽时间进行验证) 1. 基本用法 添加依赖 &l ...
- 使用Redisson实现分布式锁
原文:https://www.jianshu.com/p/cde0700f0128 1. 可重入锁(Reentrant Lock) Redisson的分布式可重入锁RLock Java对象实现了jav ...
- Java之——redis并发读写锁,使用Redisson实现分布式锁
原文:http://blog.csdn.net/l1028386804/article/details/73523810 1. 可重入锁(Reentrant Lock) Redisson的分布式可重入 ...
- 【连载】redis库存操作,分布式锁的四种实现方式[二]--基于Redisson实现分布式锁
一.redisson介绍 redisson实现了分布式和可扩展的java数据结构,支持的数据结构有:List, Set, Map, Queue, SortedSet, ConcureentMap, L ...
- 使用Apache,压力测试redisson的一般高并发
安装 Linux linux直接yum -y install httpd-tools,然后ab -V测试 Windows 1查看80端口有没有被占用,netstat -ano | findstr &q ...
- 【高并发】你知道吗?大家都在使用Redisson实现分布式锁了!!
写在前面 忘记之前在哪个群里有朋友在问:有出分布式锁的文章吗-@冰河?我的回答是:这周会有,也是[高并发]专题的.想了想,还是先发一个如何使用Redisson实现分布式锁的文章吧?为啥?因为使用Red ...
- 又长又细,万字长文带你解读Redisson分布式锁的源码
前言 上一篇文章写了Redis分布式锁的原理和缺陷,觉得有些不过瘾,只是简单的介绍了下Redisson这个框架,具体的原理什么的还没说过呢.趁年前项目忙的差不多了,反正闲着也是闲着,不如把Rediss ...
- 分布式锁中的王者方案-Redisson
上篇讲解了如何用 Redis 实现分布式锁的五种方案,但我们还是有更优的王者方案,就是用 Redisson. 缓存系列文章: 缓存实战(一):20 图 |6 千字|缓存实战(上篇) 缓存实战(二):R ...
随机推荐
- c语言l博客作业03
问题 答案 这个作业属于哪个课程 c语言程序设计ll 这个作业要求在哪里 https://edu.cnblogs.com/campus/zswxy/SE2019-3/homework/8727 我在这 ...
- 原创001 | 搭上SpringBoot自动注入源码分析专车
前言 如果这是你第二次看到师长的文章,说明你在觊觎我的美色!O(∩_∩)O哈哈~ 点赞+关注再看,养成习惯 没别的意思,就是需要你的窥屏^_^ 本系列为SpringBoot深度源码专车系列,第一篇发车 ...
- PyCharm 2019.3激活破解教程(永久)
2019.12.02 jetbrains公司发布了Python的最强编辑器PyCharm 2019.3版本.本次大版本主要对Jupyter notebooks .MongoDB.Python3.8功能 ...
- 挑战10个最难的Java面试题(附答案)【上】
欢迎添加华为云小助手微信(微信号:HWCloud002 或 HWCloud003),验证通过后,输入关键字"加群",加入华为云线上技术讨论群:输入关键字"最新活动&quo ...
- 解密国内BAT等大厂前端技术体系-百度篇(长文建议收藏)
1 引言 整个业界在前端框架不断迭代中,也寻找到了许多突破方向,例如跨平台中的RN.Flutter,服务端GraphQL.Serverless,前端和客户端的融合越来越紧密,前端在Node和Elect ...
- Xcode中.a文件引起的错误
一. TARGETS -> Build Settings-> Search Paths下 1. Library Search Paths 删除不存在的路径,保留.a文件的路径(此 ...
- BOM对象学习
location,history,screen <!DOCTYPE html> <html> <head> <meta charset="utf-8 ...
- 菜鸟系列docker——docker网络(8)
Docker网络 Docker在容器内部运行应用,这些应用之间的交互依赖于大量不同的网络,这意味着Docker需要强大的网络功能. Docker 网络从覆盖范围可分为单个 host 上的容器网络和跨多 ...
- 最高分辨率行间转移CCD图像传感器 - KAI-47051 演示视频
http://www.onsemi.cn/PowerSolutions/supportVideo.do?docId=1002912
- harbor部署常见的错误
总结部署harbor过程所遇到的一些坑 1:在使用docker push镜像的时候提示:denied: requested access to the resource is denied,用户和 ...