Redisson基本用法

2019-08-09 00:00:00 用法 Redisson

《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中提供了好多种锁,还有其它很多实用的方法

《Redisson基本用法》

《Redisson基本用法》

1.2.1.  Lock

默认,非公平锁

最简洁的一种方法

《Redisson基本用法》

指定超时时间 

《Redisson基本用法》

异步

《Redisson基本用法》

1.2.2  Fair Lock 

《Redisson基本用法》

《Redisson基本用法》

1.2.3  MultiLock

《Redisson基本用法》

1.2.4  RedLock

《Redisson基本用法》

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: 8080
 3 spring:
 4   application:
 5     name: cjs-redisson-example
 6   redis:
 7     cluster:
 8       nodes: 10.0.29.30:6379, 10.0.29.95:6379, 10.0.29.205:6379
 9     lettuce:
10       pool:
11         min-idle: 0
12         max-idle: 8
13         max-active: 20
14   datasource:
15     url: jdbc:mysql://127.0.0.1:3306/test
16     username: root
17     password: 123456
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(2000)
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(10, 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(10, 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 0;
27         }
28         return Integer.valueOf(value);
29     }
30 
31     @Override
32     public boolean decrease(Integer productId) {
33         int stock = getByProduct(productId);
34         if (stock <= 0) {
35             return false;
36         }
37         HashOperations<String, String, String> hashOperations = stringRedisTemplate.opsForHash();
38         hashOperations.put(RedisKeyPrefixConstant.STOCK, String.valueOf(productId), String.valueOf(stock - 1));
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 <= 0) {
40             return null;
41         }
42 
43         // 如果不加锁,必然超卖
44 
45         RLock lock = redissonClient.getLock("stock:" + productId);
46 
47         try {
48             lock.lock(10, 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 = 0;
 3 
 4 -- ----------------------------
 5 -- Table structure for t_course
 6 -- ----------------------------
 7 DROP TABLE IF EXISTS `t_course`;
 8 CREATE TABLE `t_course` (
 9   `id` int(11) NOT NULL AUTO_INCREMENT,
10   `course_name` varchar(64) NOT NULL,
11   `course_type` tinyint(4) NOT NULL DEFAULT '1',
12   `start_time` datetime NOT NULL,
13   PRIMARY KEY (`id`)
14 ) ENGINE=InnoDB AUTO_INCREMENT=2 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(11) NOT NULL AUTO_INCREMENT,
22   `order_no` varchar(256) CHARACTER SET latin1 NOT NULL,
23   `user_id` int(11) NOT NULL,
24   `product_id` int(11) 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=109 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(11) NOT NULL AUTO_INCREMENT,
36   `user_id` int(11) NOT NULL,
37   `course_id` int(11) NOT NULL,
38   `study_process` int(11) NOT NULL,
39   PRIMARY KEY (`id`)
40 ) ENGINE=InnoDB AUTO_INCREMENT=103 DEFAULT CHARSET=utf8mb4;
41 
42 SET FOREIGN_KEY_CHECKS = 1; 

1.4  工程结构

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

《Redisson基本用法》

1.5  Redis集群创建

《Redisson基本用法》

《Redisson基本用法》

《Redisson基本用法》

《Redisson基本用法》

《Redisson基本用法》

《Redisson基本用法》

《Redisson基本用法》

1.6  测试

测试/course/upload

《Redisson基本用法》

测试/order/create

《Redisson基本用法》

《Redisson基本用法》

《Redisson基本用法》

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 

 

相关文章