Redissonの基本的な使用法

1.リディソン

Redissonは、Redisによって正式に推奨されているJava Edition用のRedisクライアントです。多くの機能を備えており、非常に強力ですが、ここでは分散ロック機能のみを使用します。

https://github.com/redisson/redisson

1.1。基本的な使用法

<dependency> 
    <groupId> org.redisson </ groupId> 
    <artifactId> redisson </ artifactId> 
    <version> 3.11.1 </ version> 
 </ dependency>

1.2。分散ロックとシンクロナイザー

RedissonClientは多くの種類のロックを提供し、他にも多くの実用的な方法があります

1.2.1。ロック

デフォルト、不当なロック

最も簡潔な方法

タイムアウト期間を指定する 

非同期

1.2.2フェアロック 

1.2.3マルチロック

1.2.4 RedLock

1.3。例

pom.xml

 <?xml version="1.0" encoding="UTF-8"?>
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
     <parent>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-parent</artifactId>
         <version>2.1.6.RELEASE</version>
         <relativePath/> <!-- lookup parent from repository -->
     </parent>
     <groupId>com.cjs.example</groupId>
     <artifactId>cjs-redisson-example</artifactId>
     <version>0.0.1-SNAPSHOT</version>
     <name>cjs-redisson-example</name>
 
     <properties>
         <java.version>1.8</java.version>
     </properties>
 
     <dependencies>
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-data-jpa</artifactId>
         </dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-data-redis</artifactId>
         </dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-web</artifactId>
         </dependency>
 
         <!-- https://github.com/redisson/redisson#quick-start -->
         <dependency>
             <groupId>org.redisson</groupId>
             <artifactId>redisson</artifactId>
             <version>3.11.1</version>
         </dependency>
 
 
         <dependency>
             <groupId>org.apache.commons</groupId>
             <artifactId>commons-lang3</artifactId>
             <version>3.9</version>
         </dependency>
         <dependency>
             <groupId>com.alibaba</groupId>
             <artifactId>fastjson</artifactId>
             <version>1.2.58</version>
         </dependency>
         <dependency>
             <groupId>org.apache.commons</groupId>
             <artifactId>commons-pool2</artifactId>
             <version>2.6.2</version>
         </dependency>
 
         <dependency>
             <groupId>mysql</groupId>
             <artifactId>mysql-connector-java</artifactId>
             <scope>runtime</scope>
         </dependency>
         <dependency>
             <groupId>org.projectlombok</groupId>
             <artifactId>lombok</artifactId>
             <optional>true</optional>
         </dependency>
     </dependencies>
 
     <build>
         <plugins>
             <plugin>
                 <groupId>org.springframework.boot</groupId>
                 <artifactId>spring-boot-maven-plugin</artifactId>
             </plugin>
         </plugins>
     </build>
 
 </project>

application.yml

 server:
   port: 8080
 spring:
   application:
     name: cjs-redisson-example
   redis:
     cluster:
       nodes: 10.0.29.30:6379, 10.0.29.95:6379, 10.0.29.205:6379
     lettuce:
       pool:
         min-idle: 0
         max-idle: 8
         max-active: 20
   datasource:
     url: jdbc:mysql://127.0.0.1:3306/test
     username: root
     password: 123456
     driver-class-name: com.mysql.cj.jdbc.Driver
     type: com.zaxxer.hikari.HikariDataSource

 RedissonConfig.java

 package com.cjs.example.lock.config;
 
 import org.redisson.Redisson;
 import org.redisson.api.RedissonClient;
 import org.redisson.config.Config;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 
 /**
  * @author ChengJianSheng
  * @date 2019-07-26
  */
 @Configuration
 public class RedissonConfig {
 
     @Bean
     public RedissonClient redissonClient() {
         Config config = new Config();
         config.useClusterServers()
                 .setScanInterval(2000)
                 .addNodeAddress("redis://10.0.29.30:6379", "redis://10.0.29.95:6379")
                 .addNodeAddress("redis://10.0.29.205:6379");
 
         RedissonClient redisson = Redisson.create(config);
 
         return redisson;
     }
 
 }

CourseServiceImpl.java 

package com.cjs.example.lock.service.impl;
 
 import com.alibaba.fastjson.JSON;
 import com.cjs.example.lock.constant.RedisKeyPrefixConstant;
 import com.cjs.example.lock.model.CourseModel;
 import com.cjs.example.lock.model.CourseRecordModel;
 import com.cjs.example.lock.repository.CourseRecordRepository;
 import com.cjs.example.lock.repository.CourseRepository;
 import com.cjs.example.lock.service.CourseService;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.redisson.api.RLock;
 import org.redisson.api.RedissonClient;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.redis.core.HashOperations;
 import org.springframework.data.redis.core.StringRedisTemplate;
 import org.springframework.stereotype.Service;
 
 import java.util.concurrent.TimeUnit;
 
 /**
  * @author ChengJianSheng
  * @date 2019-07-26
  */
 @Slf4j
 @Service
 public class CourseServiceImpl implements CourseService {
 
     @Autowired
     private CourseRepository courseRepository;
     @Autowired
     private CourseRecordRepository courseRecordRepository;
     @Autowired
     private StringRedisTemplate stringRedisTemplate;
     @Autowired
     private RedissonClient redissonClient;
 
     @Override
     public CourseModel getById(Integer courseId) {
 
         CourseModel courseModel = null;
 
         HashOperations<String, String, String> hashOperations = stringRedisTemplate.opsForHash();
 
         String value = hashOperations.get(RedisKeyPrefixConstant.COURSE, String.valueOf(courseId));
 
         if (StringUtils.isBlank(value)) {
             String lockKey = RedisKeyPrefixConstant.LOCK_COURSE + courseId;
             RLock lock = redissonClient.getLock(lockKey);
             try {
                 boolean res = lock.tryLock(10, TimeUnit.SECONDS);
                 if (res) {
                     value = hashOperations.get(RedisKeyPrefixConstant.COURSE, String.valueOf(courseId));
                     if (StringUtils.isBlank(value)) {
                         log.info("从数据库中读取");
                         courseModel = courseRepository.findById(courseId).orElse(null);
                         hashOperations.put(RedisKeyPrefixConstant.COURSE, String.valueOf(courseId), JSON.toJSONString(courseModel));
                     }
                 }
             } catch (InterruptedException e) {
                 e.printStackTrace();
             } finally {
                 lock.unlock();
             }
         } else {
             log.info("从缓存中读取");
             courseModel = JSON.parseObject(value, CourseModel.class);
         }
 
         return courseModel;
     }
 
     @Override
     public void upload(Integer userId, Integer courseId, Integer studyProcess) {
 
         HashOperations<String, String, String> hashOperations = stringRedisTemplate.opsForHash();
 
         String cacheKey = RedisKeyPrefixConstant.COURSE_PROGRESS + ":" + userId;
         String cacheValue = hashOperations.get(cacheKey, String.valueOf(courseId));
         if (StringUtils.isNotBlank(cacheValue) && studyProcess <= Integer.valueOf(cacheValue)) {
             return;
         }
 
         String lockKey = "upload:" + userId + ":" + courseId;
 
         RLock lock = redissonClient.getLock(lockKey);
 
         try {
             lock.lock(10, TimeUnit.SECONDS);
 
             cacheValue = hashOperations.get(cacheKey, String.valueOf(courseId));
             if (StringUtils.isBlank(cacheValue) || studyProcess > Integer.valueOf(cacheValue)) {
                 CourseRecordModel model = new CourseRecordModel();
                 model.setUserId(userId);
                 model.setCourseId(courseId);
                 model.setStudyProcess(studyProcess);
                 courseRecordRepository.save(model);
                 hashOperations.put(cacheKey, String.valueOf(courseId), String.valueOf(studyProcess));
             }
 
         } catch (Exception ex) {
             log.error("获取所超时!", ex);
         } finally {
             lock.unlock();
         }
 
     }
 }

StockServiceImpl.java

 package com.cjs.example.lock.service.impl;
 
 import com.cjs.example.lock.constant.RedisKeyPrefixConstant;
 import com.cjs.example.lock.service.StockService;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.redis.core.HashOperations;
 import org.springframework.data.redis.core.StringRedisTemplate;
 import org.springframework.stereotype.Service;
 
 /**
  * @author ChengJianSheng
  * @date 2019-07-26
  */
 @Service
 public class StockServiceImpl implements StockService {
 
     @Autowired
     private StringRedisTemplate stringRedisTemplate;
 
     @Override
     public int getByProduct(Integer productId) {
         HashOperations<String, String, String> hashOperations = stringRedisTemplate.opsForHash();
         String value = hashOperations.get(RedisKeyPrefixConstant.STOCK, String.valueOf(productId));
         if (StringUtils.isBlank(value)) {
             return 0;
         }
         return Integer.valueOf(value);
     }
 
     @Override
     public boolean decrease(Integer productId) {
         int stock = getByProduct(productId);
         if (stock <= 0) {
             return false;
         }
         HashOperations<String, String, String> hashOperations = stringRedisTemplate.opsForHash();
         hashOperations.put(RedisKeyPrefixConstant.STOCK, String.valueOf(productId), String.valueOf(stock - 1));
         return true;
     }
 }

OrderServiceImpl.java

 package com.cjs.example.lock.service.impl;
 
 import com.cjs.example.lock.model.OrderModel;
 import com.cjs.example.lock.repository.OrderRepository;
 import com.cjs.example.lock.service.OrderService;
 import com.cjs.example.lock.service.StockService;
 import lombok.extern.slf4j.Slf4j;
 import org.redisson.api.RLock;
 import org.redisson.api.RedissonClient;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import java.util.Date;
 import java.util.UUID;
 import java.util.concurrent.TimeUnit;
 
 /**
  * @author ChengJianSheng
  * @date 2019-07-30
  */
 @Slf4j
 @Service
 public class OrderServiceImpl implements OrderService {
 
     @Autowired
     private StockService stockService;
     @Autowired
     private OrderRepository orderRepository;
     @Autowired
     private RedissonClient redissonClient;
 
     /**
      * 乐观锁
      */
     @Override
     public String save(Integer userId, Integer productId) {
         int stock = stockService.getByProduct(productId);
         log.info("剩余库存:{}", stock);
         if (stock <= 0) {
             return null;
         }
 
         //  如果不加锁,必然超卖
 
         RLock lock = redissonClient.getLock("stock:" + productId);
 
         try {
             lock.lock(10, TimeUnit.SECONDS);
 
             String orderNo = UUID.randomUUID().toString().replace("-", "").toUpperCase();
 
             if (stockService.decrease(productId)) {
 
                 OrderModel orderModel = new OrderModel();
                 orderModel.setUserId(userId);
                 orderModel.setProductId(productId);
                 orderModel.setOrderNo(orderNo);
                 Date now = new Date();
                 orderModel.setCreateTime(now);
                 orderModel.setUpdateTime(now);
                 orderRepository.save(orderModel);
 
                 return orderNo;
             }
 
         } catch (Exception ex) {
             log.error("下单失败", ex);
         } finally {
             lock.unlock();
         }
 
         return null;
     }
 
 }

OrderModel.java

 1 
package com.cjs.example.lock.model;
  
  import lombok.Data;
 
  import javax.persistence.*;
  import java.io.Serializable;
  import java.util.Date;
  
  /**
  * @author ChengJianSheng
  * @date 2019-07-30
  */
 @Data
 @Entity
 @Table(name = "t_order")
 public class OrderModel implements Serializable {
 
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Integer id;
 
     @Column(name = "order_no")
     private String orderNo;
 
    @Column(name = "product_id")
     private Integer productId;
 
     @Column(name = "user_id")
    private Integer userId;

     @Column(name = "create_time")
     private Date createTime;
 
     @Column(name = "update_time")
     private Date updateTime;
 } 

データベースscript.sql

SET NAMES utf8mb4;
 SET FOREIGN_KEY_CHECKS = 0;
  
  -- ----------------------------
  -- Table structure for t_course
  -- ----------------------------
  DROP TABLE IF EXISTS `t_course`;
  CREATE TABLE `t_course` (
   `id` int(11) NOT NULL AUTO_INCREMENT,
   `course_name` varchar(64) NOT NULL,
   `course_type` tinyint(4) NOT NULL DEFAULT '1',
   `start_time` datetime NOT NULL,
   PRIMARY KEY (`id`)
 ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4;
 
 -- ----------------------------
 -- Table structure for t_order
 -- ----------------------------
 DROP TABLE IF EXISTS `t_order`;
 CREATE TABLE `t_order` (
   `id` int(11) NOT NULL AUTO_INCREMENT,
   `order_no` varchar(256) CHARACTER SET latin1 NOT NULL,
   `user_id` int(11) NOT NULL,
   `product_id` int(11) NOT NULL,
   `create_time` datetime NOT NULL,
   `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
   PRIMARY KEY (`id`)
 ) ENGINE=InnoDB AUTO_INCREMENT=109 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
 
 -- ----------------------------
 -- Table structure for t_user_course_record
 -- ----------------------------
 DROP TABLE IF EXISTS `t_user_course_record`;
 CREATE TABLE `t_user_course_record` (
   `id` int(11) NOT NULL AUTO_INCREMENT,
   `user_id` int(11) NOT NULL,
   `course_id` int(11) NOT NULL,
   `study_process` int(11) NOT NULL,
   PRIMARY KEY (`id`)
 ) ENGINE=InnoDB AUTO_INCREMENT=103 DEFAULT CHARSET=utf8mb4;
 
 SET FOREIGN_KEY_CHECKS = 1; 

1.4エンジニアリング構造

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

1.5 Redisクラスターの作成

1.6テスト

テスト/コース/アップロード

テスト/注文/作成

2. Springの統合

使い方はRedissonに似ています

<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-integration</artifactId>
 </dependency>
 <dependency>
     <groupId>org.springframework.integration</groupId>
     <artifactId>spring-integration-redis</artifactId>
 </dependency>
 package com.kaishustory.base.conf;
 
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.data.redis.connection.RedisConnectionFactory;
 import org.springframework.integration.redis.util.RedisLockRegistry;
 
 /**
  * @author ChengJianSheng
  * @date 2019-07-30
  */
 @Configuration
 public class RedisLockConfig {
 
     @Bean
     public RedisLockRegistry redisLockRegistry(RedisConnectionFactory redisConnectionFactory) {
         return new RedisLockRegistry(redisConnectionFactory, "asdf")
     }
 
 }
 @Autowired
 private RedisLockRegistry redisLockRegistry;
 
 public void save(Integer userId) {
 
     String lockKey = "order:" + userId;
 
     Lock lock = redisLockRegistry.obtain(lockKey);
     try {
         lock.lock();
 
         //todo
 
     } finally {
         lock.unlock();
     }
 
 }

3.その他

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

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

おすすめ

転載: blog.csdn.net/mrlin6688/article/details/106074547