<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Spring Boot 操作 Redis 的各種實(shí)現(xiàn)

          共 27053字,需瀏覽 55分鐘

           ·

          2021-09-03 10:44

          點(diǎn)擊關(guān)注公眾號,Java干貨及時(shí)送達(dá)

          牛逼!又發(fā)現(xiàn)了一款面試題庫,太全了??!

          點(diǎn)擊查看


          一、Jedis,Redisson,Lettuce三者的區(qū)別

          共同點(diǎn):都提供了基于Redis操作的Java API,只是封裝程度,具體實(shí)現(xiàn)稍有不同。

          不同點(diǎn):

          1.1、Jedis

          是Redis的Java實(shí)現(xiàn)的客戶端。支持基本的數(shù)據(jù)類型如:String、Hash、List、Set、Sorted Set。

          特點(diǎn):使用阻塞的I/O,方法調(diào)用同步,程序流需要等到socket處理完I/O才能執(zhí)行,不支持異步操作。Jedis客戶端實(shí)例不是線程安全的,需要通過連接池來使用Jedis。

          1.2、Redisson

          優(yōu)點(diǎn)點(diǎn):分布式鎖,分布式集合,可通過Redis支持延遲隊(duì)列。

          1.3、 Lettuce

          用于線程安全同步,異步和響應(yīng)使用,支持集群,Sentinel,管道和編碼器。

          基于Netty框架的事件驅(qū)動(dòng)的通信層,其方法調(diào)用是異步的。Lettuce的API是線程安全的,所以可以操作單個(gè)Lettuce連接來完成各種操作。

          二、RedisTemplate

          2.1、使用配置

          maven配置引入,(要加上版本號,我這里是因?yàn)镻arent已聲明)

          <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-data-redis</artifactId>
          </dependency>

          application-dev.yml

          spring:
            redis:
              host: 192.168.1.140
              port: 6379
              password:
              database: 15 # 指定redis的分庫(共16個(gè)0到15)

          2.2、使用示例

           @Resource
           private StringRedisTemplate stringRedisTemplate;
           
              @Override
              public CustomersEntity findById(Integer id) {
                  // 需要緩存
                  // 所有涉及的緩存都需要?jiǎng)h除,或者更新
                  try {
                      String toString = stringRedisTemplate.opsForHash().get(REDIS_CUSTOMERS_ONE, id + "").toString();
                      if (toString != null) {
                          return JSONUtil.toBean(toString, CustomersEntity.class);
                      }
                  } catch (Exception e) {
                      e.printStackTrace();
                  }
                  // 緩存為空的時(shí)候,先查,然后緩存redis
                  Optional<CustomersEntity> byId = customerRepo.findById(id);
                  if (byId.isPresent()) {
                      CustomersEntity customersEntity = byId.get();
                      try {
                          stringRedisTemplate.opsForHash().put(REDIS_CUSTOMERS_ONE, id + "", JSONUtil.toJsonStr(customersEntity));
                      } catch (Exception e) {
                          e.printStackTrace();
                      }
                      return customersEntity;
                  }
                  return null;
              }

          2.3、擴(kuò)展

          2.3.1、spring-boot-starter-data-redis的依賴包

          3.3.2、stringRedisTemplate API(部分展示)
          • opsForHash --> hash操作

          • opsForList --> list操作

          • opsForSet --> set操作

          • opsForValue --> string操作

          • opsForZSet --> Zset操作

          3.3.3 StringRedisTemplate默認(rèn)序列化機(jī)制

          public class StringRedisTemplate extends RedisTemplate<StringString{

           /**
            * Constructs a new <code>StringRedisTemplate</code> instance. {@link #setConnectionFactory(RedisConnectionFactory)}
            * and {@link #afterPropertiesSet()} still need to be called.
            */

           public StringRedisTemplate() {
            RedisSerializer<String> stringSerializer = new StringRedisSerializer();
            setKeySerializer(stringSerializer);
            setValueSerializer(stringSerializer);
            setHashKeySerializer(stringSerializer);
            setHashValueSerializer(stringSerializer);
           }
           }

          三、RedissonClient 操作示例

          3.1 基本配置

          3.1.1、Maven pom 引入

          <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-data-redis</artifactId>
          </dependency>
          <dependency>
              <groupId>org.redisson</groupId>
              <artifactId>redisson</artifactId>
              <version>3.8.2</version>
              <optional>true</optional>
          </dependency>
          <dependency>
              <groupId>org.redisson</groupId>
              <artifactId>redisson-spring-boot-starter</artifactId>
              <version>LATEST</version>
          </dependency>

          3.1.2、添加配置文件Yaml或者json格式

          redisson-config.yml

          # Redisson 配置
          singleServerConfig:
            address: "redis://192.168.1.140:6379"
            password: null
            clientName: null
            database: 15 #選擇使用哪個(gè)數(shù)據(jù)庫0~15
            idleConnectionTimeout: 10000
            pingTimeout: 1000
            connectTimeout: 10000
            timeout: 3000
            retryAttempts: 3
            retryInterval: 1500
            reconnectionTimeout: 3000
            failedAttempts: 3
            subscriptionsPerConnection: 5
            subscriptionConnectionMinimumIdleSize: 1
            subscriptionConnectionPoolSize: 50
            connectionMinimumIdleSize: 32
            connectionPoolSize: 64
            dnsMonitoringInterval: 5000
            #dnsMonitoring: false

          threads: 0
          nettyThreads: 0
          codec:
            class: "org.redisson.codec.JsonJacksonCodec"
          transportMode: "NIO"

          或者,配置 redisson-config.json

          {
            "singleServerConfig": {
              "idleConnectionTimeout"10000,
              "pingTimeout"1000,
              "connectTimeout"10000,
              "timeout"3000,
              "retryAttempts"3,
              "retryInterval"1500,
              "reconnectionTimeout"3000,
              "failedAttempts"3,
              "password"null,
              "subscriptionsPerConnection"5,
              "clientName"null,
              "address""redis://192.168.1.140:6379",
              "subscriptionConnectionMinimumIdleSize"1,
              "subscriptionConnectionPoolSize"50,
              "connectionMinimumIdleSize"10,
              "connectionPoolSize"64,
              "database"0,
              "dnsMonitoring"false,
              "dnsMonitoringInterval"5000
            },
            "threads"0,
            "nettyThreads"0,
            "codec"null,
            "useLinuxNativeEpoll"false
          }

          3.1.3、讀取配置

          新建讀取配置類

          @Configuration
          public class RedissonConfig {

              @Bean
              public RedissonClient redisson() throws IOException {

                  // 兩種讀取方式,Config.fromYAML 和 Config.fromJSON
          //        Config config = Config.fromJSON(RedissonConfig.class.getClassLoader().getResource("redisson-config.json"));
                  Config config = Config.fromYAML(RedissonConfig.class.getClassLoader().getResource("redisson-config.yml"));
                  return Redisson.create(config);
              }
          }

          或者,在 application.yml中配置如下

          spring:
            redis:
              redisson:
                config: classpath:redisson-config.yaml

          3.2 使用示例

          @RestController
          @RequestMapping("/")
          public class TeController {

              @Autowired
              private RedissonClient redissonClient;

              static long i = 20;
              static long sum = 300;

          //    ========================== String =======================
              @GetMapping("/set/{key}")
              public String s1(@PathVariable String key) {
                  // 設(shè)置字符串
                  RBucket<String> keyObj = redissonClient.getBucket(key);
                  keyObj.set(key + "1-v1");
                  return key;
              }

              @GetMapping("/get/{key}")
              public String g1(@PathVariable String key) {
                  // 設(shè)置字符串
                  RBucket<String> keyObj = redissonClient.getBucket(key);
                  String s = keyObj.get();
                  return s;
              }

              //    ========================== hash =======================-=

              @GetMapping("/hset/{key}")
              public String h1(@PathVariable String key) {

                  Ur ur = new Ur();
                  ur.setId(MathUtil.randomLong(1,20));
                  ur.setName(key);
                // 存放 Hash
                  RMap<String, Ur> ss = redissonClient.getMap("UR");
                  ss.put(ur.getId().toString(), ur);
                  return ur.toString();
              }

              @GetMapping("/hget/{id}")
              public String h2(@PathVariable String id) {
                  // hash 查詢
                  RMap<String, Ur> ss = redissonClient.getMap("UR");
                  Ur ur = ss.get(id);
                  return ur.toString();
              }

              // 查詢所有的 keys
              @GetMapping("/all")
              public String all(){
                  RKeys keys = redissonClient.getKeys();
                  Iterable<String> keys1 = keys.getKeys();
                  keys1.forEach(System.out::println);
                  return keys.toString();
              }

              // ================== ==============讀寫鎖測試 =============================

              @GetMapping("/rw/set/{key}")
              public void rw_set(){
          //        RedissonLock.
                  RBucket<String> ls_count = redissonClient.getBucket("LS_COUNT");
                  ls_count.set("300",360000000l, TimeUnit.SECONDS);
              }

              // 減法運(yùn)算
              @GetMapping("/jf")
              public void jf(){

                  String key = "S_COUNT";

          //        RAtomicLong atomicLong = redissonClient.getAtomicLong(key);
          //        atomicLong.set(sum);
          //        long l = atomicLong.decrementAndGet();
          //        System.out.println(l);

                  RAtomicLong atomicLong = redissonClient.getAtomicLong(key);
                  if (!atomicLong.isExists()) {
                      atomicLong.set(300l);
                  }

                  while (i == 0) {
                      if (atomicLong.get() > 0) {
                          long l = atomicLong.getAndDecrement();
                                  try {
                                      Thread.sleep(1000l);
                                  } catch (InterruptedException e) {
                                      e.printStackTrace();
                                  }
                          i --;
                          System.out.println(Thread.currentThread().getName() + "->" + i + "->" + l);
                      }
                  }


              }

              @GetMapping("/rw/get")
              public String rw_get(){

                  String key = "S_COUNT";
                  Runnable r = new Runnable() {
                      @Override
                      public void run() {
                          RAtomicLong atomicLong = redissonClient.getAtomicLong(key);
                          if (!atomicLong.isExists()) {
                              atomicLong.set(300l);
                          }
                          if (atomicLong.get() > 0) {
                              long l = atomicLong.getAndDecrement();
                              i --;
                              System.out.println(Thread.currentThread().getName() + "->" + i + "->" + l);
                          }
                      }
                  };

                  while (i != 0) {
                      new Thread(r).start();
          //            new Thread(r).run();
          //            new Thread(r).run();
          //            new Thread(r).run();
          //            new Thread(r).run();
                  }


                  RBucket<String> bucket = redissonClient.getBucket(key);
                  String s = bucket.get();
                  System.out.println("================線程已結(jié)束================================" + s);

                  return s;
              }

          }

          4.3 擴(kuò)展

          4.3.1 豐富的jar支持,尤其是對 Netty NIO框架

          4.3.2 豐富的配置機(jī)制選擇,這里是詳細(xì)的配置說明

          https://github.com/redisson/redisson/wiki/2.-Configuration

          關(guān)于序列化機(jī)制中,就有很多

          4.3.3 API支持(部分展示),具體的 Redis --> RedissonClient ,可查看這里

          https://github.com/redisson/redisson/wiki/11.-Redis-commands-mapping


          4.3.4 輕便的豐富的鎖機(jī)制的實(shí)現(xiàn)

          • Lock

          • Fair Lock

          • MultiLock

          • RedLock

          • ReadWriteLock

          • Semaphore

          • PermitExpirableSemaphore

          • CountDownLatch

          四、基于注解實(shí)現(xiàn)的Redis緩存

          4.1 Maven 和 YML配置

          參考 RedisTemplate 配置。另外,還需要額外的配置類

          // todo 定義序列化,解決亂碼問題
          @EnableCaching
          @Configuration
          @ConfigurationProperties(prefix = "spring.cache.redis")
          public class RedisCacheConfig {

              private Duration timeToLive = Duration.ZERO;

              public void setTimeToLive(Duration timeToLive) {
                  this.timeToLive = timeToLive;
              }

              @Bean
              public CacheManager cacheManager(RedisConnectionFactory factory) {
                  RedisSerializer<String> redisSerializer = new StringRedisSerializer();
                  Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);

                  // 解決查詢緩存轉(zhuǎn)換異常的問題
                  ObjectMapper om = new ObjectMapper();
                  om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
                  om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
                  jackson2JsonRedisSerializer.setObjectMapper(om);

                  // 配置序列化(解決亂碼的問題)
                  RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                          .entryTtl(timeToLive)
                          .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
                          .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
                          .disableCachingNullValues();

                  RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
                          .cacheDefaults(config)
                          .build();
                  return cacheManager;
              }

          }

          4.2 使用示例

          @Transactional
          @Service
          public class ReImpl implements RedisService {

              @Resource
              private CustomerRepo customerRepo;
              @Resource
              private StringRedisTemplate stringRedisTemplate;

              public static final String REDIS_CUSTOMERS_ONE = "Customers";

              public static final String REDIS_CUSTOMERS_ALL = "allList";

              // =====================================================================使用Spring cahce 注解方式實(shí)現(xiàn)緩存
              // ==================================單個(gè)操作

              @Override
              @Cacheable(value = "cache:customer", unless = "null == #result",key = "#id")
              public CustomersEntity cacheOne(Integer id) {
                  final Optional<CustomersEntity> byId = customerRepo.findById(id);
                  return byId.isPresent() ? byId.get() : null;
              }

              @Override
              @Cacheable(value = "cache:customer", unless = "null == #result", key = "#id")
              public CustomersEntity cacheOne2(Integer id) {
                  final Optional<CustomersEntity> byId = customerRepo.findById(id);
                  return byId.isPresent() ? byId.get() : null;
              }

               // todo 自定義redis緩存的key,
              @Override
              @Cacheable(value = "cache:customer", unless = "null == #result", key = "#root.methodName + '.' + #id")
              public CustomersEntity cacheOne3(Integer id) {
                  final Optional<CustomersEntity> byId = customerRepo.findById(id);
                  return byId.isPresent() ? byId.get() : null;
              }

              // todo 這里緩存到redis,還有響應(yīng)頁面是String(加了很多轉(zhuǎn)義符\,),不是Json格式
              @Override
              @Cacheable(value = "cache:customer", unless = "null == #result", key = "#root.methodName + '.' + #id")
              public String cacheOne4(Integer id) {
                  final Optional<CustomersEntity> byId = customerRepo.findById(id);
                  return byId.map(JSONUtil::toJsonStr).orElse(null);
              }

               // todo 緩存json,不亂碼已處理好,調(diào)整序列化和反序列化
              @Override
              @Cacheable(value = "cache:customer", unless = "null == #result", key = "#root.methodName + '.' + #id")
              public CustomersEntity cacheOne5(Integer id) {
                  Optional<CustomersEntity> byId = customerRepo.findById(id);
                  return byId.filter(obj -> !StrUtil.isBlankIfStr(obj)).orElse(null);
              }



              // ==================================刪除緩存
              @Override
              @CacheEvict(value = "cache:customer", key = "'cacheOne5' + '.' + #id")
              public Object del(Integer id) {
                  // 刪除緩存后的邏輯
                  return null;
              }

              @Override
              @CacheEvict(value = "cache:customer",allEntries = true)
              public void del() {

              }

              @CacheEvict(value = "cache:all",allEntries = true)
              public void delall() {

              }
              // ==================List操作

              @Override
              @Cacheable(value = "cache:all")
              public List<CustomersEntity> cacheList() {
                  List<CustomersEntity> all = customerRepo.findAll();
                  return all;
              }

              // todo 先查詢緩存,再校驗(yàn)是否一致,然后更新操作,比較實(shí)用,要清楚緩存的數(shù)據(jù)格式(明確業(yè)務(wù)和緩存模型數(shù)據(jù))
              @Override
              @CachePut(value = "cache:all",unless = "null == #result",key = "#root.methodName")
              public List<CustomersEntity> cacheList2() {
                  List<CustomersEntity> all = customerRepo.findAll();
                  return all;
              }

          }

          4.3 擴(kuò)展

          基于spring緩存實(shí)現(xiàn)

          來源:blog.csdn.net/qq_42105629/article/details/102589319

          如有文章對你有幫助,

          歡迎關(guān)注??、點(diǎn)贊??、轉(zhuǎn)發(fā)??!


          推薦, Java面試題庫,詳情點(diǎn)擊:
          牛逼!又發(fā)現(xiàn)了一款牛逼的Java面試題庫,史上最強(qiáng)!

          點(diǎn)擊文末“閱讀原文”可直達(dá)

          瀏覽 52
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美精品一级二级A片 | 日本内射网站 | 人操人人射人 | 成人性爱免费 | 麻豆传媒换妻 |