八卦阵 发表于 昨天 16:03

Redisson 总结

1. 底子使用

1.1 引入依赖

<dependencies>
      <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson-spring-boot-starter</artifactId>
      </dependency>
</dependencies>
包含的依赖如下
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=http%3A%2F%2Fimg.fan223.cn%2F2024%2F05%2F20240509140934.png&pos_id=img-9QZmbgZT-1726626863452
1.2 配置文件

其实默认主机就是 127.0.0.1,默认端口是 6379,一致的话可以不用配置
spring:
data:
    redis:
      host: 127.0.0.1
      password: redis
1.3 测试类

import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DemoController {

    private final RedissonClient redissonClient;

    @Autowired
    public DemoController(RedissonClient redissonClient) {
      this.redissonClient = redissonClient;
    }

    @GetMapping("/test")
    public void test() {
      RBucket<String> bucket = redissonClient.getBucket("test");
      bucket.set("hello");
    }

    @GetMapping("/get")
    public String get() {
      RBucket<String> bucket = redissonClient.getBucket("test");
      return bucket.get();
    }
}
1.4 测试

访问 /test 接口,利用 Redis 管理工具可以看到数据已经添加了进来
https://img-blog.csdnimg.cn/img_convert/27c2a0edf30b14c182ff4f8a7cf16adf.png
在访问 /get 接口,乐成获取到数据
https://img-blog.csdnimg.cn/img_convert/6fbd56c28eb0767020b2cab179369c43.png
2. 设置序列化

上面可以看到在 Redis 管理工具中查看数据是一串字符,并不直观,可以自界说数据序列化
2.1 配置类

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.codec.JsonJacksonCodec;
import org.redisson.config.Config;
import org.redisson.config.SingleServerConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RedissonConfig {

    @Bean
    public RedissonClient redissonClient() {
      Config config = new Config();
      // 单机模式
      SingleServerConfig singleServerConfig = config.useSingleServer();
      singleServerConfig.setAddress("redis://127.0.0.1:6379");
      singleServerConfig.setPassword("redis");
      // JSON序列化
      config.setCodec(new JsonJacksonCodec());

      return Redisson.create(config);
    }
}
这里已经配置了主机等相干信息,因此配置文件里的配置可以去除,或者这里直接取配置文件的值,具体根据情况选择,其他的序列化类如下
编码类名称说明org.redisson.codec.JsonJacksonCodecJackson JSON 编码org.redisson.codec.AvroJacksonCodecAvro 一种二进制的 JSON 编码org.redisson.codec.SmileJacksonCodecSmile一种 二进制的 JSON 编码org.redisson.codec.CborJacksonCodecCBOR 一种二进制的 JSON 编码org.redisson.codec.MsgPackJacksonCodecMsgPack 一种 二进制的 JSON 编码org.redisson.codec.IonJacksonCodecAmazon Ion 亚马逊的 Ion 编码,格式与 JSON 类似org.redisson.codec.KryoCodecKryo 二进制对象序列化编码org.redisson.codec.SerializationCodecJDK 序列化编码org.redisson.codec.FstCodecFST 10 倍于 JDK 序列化性能而且 100% 兼容的编码org.redisson.codec.LZ4CodecLZ4 压缩型序列化对象编码org.redisson.codec.SnappyCodecSnappy 另一个压缩型序列化对象编码org.redisson.client.codec.JsonJacksonMapCodec基于 Jackson 的映射类使用的编码,可用于避免序列化类的信息,以及用于办理使用byte[] 碰到的问题org.redisson.client.codec.StringCodec纯字符串编码(无转换)org.redisson.client.codec.LongCodec纯整长型数字编码(无转换)org.redisson.client.codec.ByteArrayCodec字节数组编码org.redisson.codec.CompositeCodec用来组合多种不同编码在一起 2.2 测试

访问 /test 接口,再查看数据可以看到已经序列化成 JSON 格式
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=http%3A%2F%2Fimg.fan223.cn%2F2024%2F05%2F20240509154909.png&pos_id=img-ru9557jX-1726626863453
3. 底子数据结构使用

3.1 String

其实上面的示例用的就是字符串操作,通过 RBucket 对象来操作字符串数据结构
创建一个实体类
import lombok.Builder;
import lombok.Data;

import java.io.Serial;
import java.io.Serializable;

@Data
@Builder
public class Article implements Serializable {

    @Serial
    private static final long serialVersionUID = -8862397425409851538L;

    private String title;

    private String content;
}
存储对象,简单示比方下:
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DemoController {

    private final RedissonClient redissonClient;

    @Autowired
    public DemoController(RedissonClient redissonClient) {
      this.redissonClient = redissonClient;
    }

    @GetMapping("/test")
    public void test() {
      RBucket<Object> bucket = redissonClient.getBucket("test");
      bucket.set(Article.builder().title("demo").content("test redisson").build());
    }
}
数据如下:
https://img-blog.csdnimg.cn/img_convert/39b72a5cb880f89ff6996652ba4553ae.png
3.2 Hash

通过 RMap 对象来操作哈希数据结构,简单示比方下:
import org.redisson.api.RMap;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DemoController {

    private final RedissonClient redissonClient;

    @Autowired
    public DemoController(RedissonClient redissonClient) {
      this.redissonClient = redissonClient;
    }

    @GetMapping("/test")
    public void test() {
      RMap<String, Article> rMap = redissonClient.getMap("test");
      rMap.put("k1", Article.builder().title("demo").content("test redisson").build());
    }
}
数据如下:
https://img-blog.csdnimg.cn/img_convert/5e5a9fd5d76068059745c9331632af83.png
3.3 List

3.3.1 无序

通过 RList 对象来操作列表数据结构,简单示比方下:
import org.redisson.api.RList;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DemoController {

    private final RedissonClient redissonClient;

    @Autowired
    public DemoController(RedissonClient redissonClient) {
      this.redissonClient = redissonClient;
    }

    @GetMapping("/test")
    public void test() {
      RList<Article> rList = redissonClient.getList("test");
      rList.add(Article.builder().title("demo").content("test redisson").build());
      rList.add(Article.builder().title("demo").content("test redisson").build());
    }
}
数据如下:
https://img-blog.csdnimg.cn/img_convert/a3439dc7757972eeb2db9322cf9d53c5.png
3.3.2 有序

通过 RSortedSet 对象来操作有序集合数据结构
改造一下实体类,实现 Comparable 接口
import lombok.Data;

import java.io.Serial;
import java.io.Serializable;

@Data
public class Article implements Serializable, Comparable<Article> {

    @Serial
    private static final long serialVersionUID = -8862397425409851538L;

    private Long id;

    private String title;

    private String content;

    @Override
    public int compareTo(Article article) {
      return this.getId().compareTo(article.getId());
    }
}
简单示比方下:
import org.redisson.api.RSortedSet;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DemoController {

    private final RedissonClient redissonClient;

    @Autowired
    public DemoController(RedissonClient redissonClient) {
      this.redissonClient = redissonClient;
    }

    @GetMapping("/test")
    public void test() {
      RSortedSet<Article> rSortedSet = redissonClient.getSortedSet("test");

      Article article1 = new Article();
      article1.setId(22L);
      article1.setTitle("demo");
      article1.setContent("test redisson");
      rSortedSet.add(article1);

      Article article2 = new Article();
      article2.setId(11L);
      article2.setTitle("demo");
      article2.setContent("test redisson");
      rSortedSet.add(article2);
    }
}
数据如下,可以看到数据根据 id 排序
https://img-blog.csdnimg.cn/img_convert/96fdecef25d32b3cef29442819ed0999.png
3.4 Set

通过 RSet 对象来操作集合数据结构,简单示比方下:
import org.redisson.api.RSet;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DemoController {

    private final RedissonClient redissonClient;

    @Autowired
    public DemoController(RedissonClient redissonClient) {
      this.redissonClient = redissonClient;
    }

    @GetMapping("/test")
    public void test() {
      RSet<Article> rSet = redissonClient.getSet("test");
      rSet.add(Article.builder().title("demo").content("test redisson").build());
      rSet.add(Article.builder().title("demo").content("test redisson").build());
    }
}
数据如下,可以看到重复数据被去除了
https://img-blog.csdnimg.cn/img_convert/fe4d0212fd776d6924da95d8019f0ed3.png
3.5 Zset

通过 RScoredSortedSet 来操作带分数的有序集合数据结构,简单示比方下:
import org.redisson.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DemoController {

    private final RedissonClient redissonClient;

    @Autowired
    public DemoController(RedissonClient redissonClient) {
      this.redissonClient = redissonClient;
    }

    @GetMapping("/test")
    public void test() {
      RScoredSortedSet<String> rScoredSortedSet = redissonClient.getScoredSortedSet("test");
      rScoredSortedSet.add(600.1, "test1");
      rScoredSortedSet.add(500.3, "test2");
      rScoredSortedSet.add(900.3, "test3");
      rScoredSortedSet.add(200.9, "test1");
    }
}
数据如下,可以看到根据分数来排序,并且重复数据被排除了
https://img-blog.csdnimg.cn/img_convert/ce85f24a622461c3b2ab425d6628194b.png
4. 布隆过滤器

可以用于检索一个元素是否在一个集合中
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.Duration;

@RestController
public class DemoController {

    private final RedissonClient redissonClient;

    @Autowired
    public DemoController(RedissonClient redissonClient) {
      this.redissonClient = redissonClient;
    }

    @GetMapping("/test")
    public void test() {
      RBloomFilter<String> rBloomFilter = redissonClient.getBloomFilter("test");
      // 初始化预期插入的数据量为10000和期望误差率为0.01
      rBloomFilter.tryInit(10000, 0.01);
      // 插入部分数据
      rBloomFilter.add("100");
      rBloomFilter.add("200");
      rBloomFilter.add("300");
      // 设置过期时间
      rBloomFilter.expire(Duration.ofSeconds(30));
      // 判断是否存在
      System.out.println(rBloomFilter.contains("300")); // true
      System.out.println(rBloomFilter.contains("200")); // true
      System.out.println(rBloomFilter.contains("999")); // false
    }
}
5. 分布式自增 ID

参考代码如下:
import org.redisson.api.RAtomicLong;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DemoController {

    private final RedissonClient redissonClient;

    @Autowired
    public DemoController(RedissonClient redissonClient) {
      this.redissonClient = redissonClient;
    }

    @GetMapping("/test")
    public void test() {
      RAtomicLong rAtomicLong = redissonClient.getAtomicLong("test");
      System.out.println(rAtomicLong.incrementAndGet());
    }
}
6. 分布式锁

6.1 未加锁情况

模仿一个库存扣减操作
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DemoController {

    private final RedissonClient redissonClient;

    @Autowired
    public DemoController(RedissonClient redissonClient) {
      this.redissonClient = redissonClient;
    }

    @GetMapping("/test")
    public void test() {
      RBucket<Integer> bucket = redissonClient.getBucket("num");
      Integer num = bucket.get();
      if (num > 0) {
            System.out.println("扣减库存, 当前库存: " + --num);
            bucket.set(num);
      } else {
            System.out.println("库存不足");
      }
    }
}
使用 Jemter 模仿并发场景
https://img-blog.csdnimg.cn/img_convert/14f1ec6114d7c56352df8aafc864b131.png
https://img-blog.csdnimg.cn/img_convert/2005e72dbf338e05ae18e1c118b055c7.png
点击运行后可以看到明显出现了并发问题
https://img-blog.csdnimg.cn/img_convert/e32c2dfb475e2917ddec8d046c6124bd.png
6.2 加锁情况

修改下库存扣减代码
import org.redisson.api.RBucket;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DemoController {

    private final RedissonClient redissonClient;

    @Autowired
    public DemoController(RedissonClient redissonClient) {
      this.redissonClient = redissonClient;
    }

    @GetMapping("/test")
    public void test() {
      RLock rLock = redissonClient.getLock("test");
      try {
            rLock.lock();
            RBucket<Integer> bucket = redissonClient.getBucket("num");
            Integer num = bucket.get();
            if (num > 0) {
                System.out.println("扣减库存, 当前库存: " + --num);
                bucket.set(num);
            } else {
                System.out.println("库存不足");
            }
      } finally {
            rLock.unlock();
      }
    }
}
再次模仿并发请求,可以看到问题已包办理
https://img-blog.csdnimg.cn/img_convert/1ca0efdbe65f7a71f58d85ce87c1b0b9.png
6.3 加锁操作耗时长

当加锁操作耗时较长时,假如多个请求进来,其他的请求会不停堵塞,可以使用 tryLock 来尝试获取锁,获取不到先返回相应
import org.redisson.api.RBucket;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DemoController {

    private final RedissonClient redissonClient;

    @Autowired
    public DemoController(RedissonClient redissonClient) {
      this.redissonClient = redissonClient;
    }

    @GetMapping("/test")
    public void test() {
      RLock rLock = redissonClient.getLock("test");
      try {
            if (rLock.tryLock()) {
                RBucket<Integer> bucket = redissonClient.getBucket("num");
                Integer num = bucket.get();
                Thread.sleep(5000);
                if (num > 0) {
                  System.out.println("扣减库存, 当前库存: " + --num);
                  bucket.set(num);
                } else {
                  System.out.println("库存不足");
                }
            } else {
                System.out.println("请稍后再试");
            }
      } catch (InterruptedException e) {
            System.out.println(e.getMessage());
            Thread.currentThread().interrupt();
      } finally {
            // 是否是锁定状态且是当前执行线程的锁
            if (rLock.isLocked() && rLock.isHeldByCurrentThread()) {
                rLock.unlock();
            }
      }
    }
}
模仿并发请求,这里将时间设置长一点,可以看到获取到锁的请求则去举行库存扣减,获取不到先返回相应
https://img-blog.csdnimg.cn/img_convert/89610a2c091483271915eb0a81fd43c2.png

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: Redisson 总结