Redisson基本用法

Redisson基本用法_第1张图片

1.  Redisson

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

https://github.com/redisson/redisson

1.1.  基本用法

 
    org.redisson
    redisson
    3.11.1
 

1.2.  Distributed locks and synchronizers

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

1.2.1.  Lock

默认,非公平锁

最简洁的一种方法

指定超时时间 

Redisson基本用法_第2张图片

异步

1.2.2  Fair Lock 

Redisson基本用法_第3张图片

1.2.3  MultiLock

Redisson基本用法_第4张图片

1.2.4  RedLock

Redisson基本用法_第5张图片

1.3.  示例

pom.xml

 
 
     4.0.0
     
         org.springframework.boot
         spring-boot-starter-parent
         2.1.6.RELEASE
          
     
     com.cjs.example
     cjs-redisson-example
     0.0.1-SNAPSHOT
     cjs-redisson-example
 
     
         1.8
     
 
     
         
             org.springframework.boot
             spring-boot-starter-data-jpa
         
         
             org.springframework.boot
             spring-boot-starter-data-redis
         
         
             org.springframework.boot
             spring-boot-starter-web
         
 
         
         
             org.redisson
             redisson
             3.11.1
         
 
 
         
             org.apache.commons
             commons-lang3
             3.9
         
         
             com.alibaba
             fastjson
             1.2.58
         
         
             org.apache.commons
             commons-pool2
             2.6.2
         
 
         
             mysql
             mysql-connector-java
             runtime
         
         
             org.projectlombok
             lombok
             true
         
     
 
     
         
             
                 org.springframework.boot
                 spring-boot-maven-plugin
             
         
     
 
 

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 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 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 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 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;
 } 

数据库脚本.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集群创建

Redisson基本用法_第6张图片

Redisson基本用法_第7张图片

Redisson基本用法_第8张图片

Redisson基本用法_第9张图片

Redisson基本用法_第10张图片

1.6  测试

测试/course/upload

Redisson基本用法_第11张图片

测试/order/create

Redisson基本用法_第12张图片

Redisson基本用法_第13张图片

Redisson基本用法_第14张图片

2.  Spring Integration

用法与Redisson类似


     org.springframework.boot
     spring-boot-starter-integration
 
 
     org.springframework.integration
     spring-integration-redis
 
 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 

你可能感兴趣的:(------【Redis】)