【Redis】Redis学習チュートリアル (7) SpringBootはRedisを統合します

前回の記事では、Redis のいくつかの機能と、主流の Java クライアント API の使用方法を詳しく紹介しました。

現在普及しているマイクロサービスや分散クラスター環境において、Redis は幅広いシナリオで使用することができ、クラスター環境のシステムで発生する多くの技術的問題を解決することができます。 :

  • 分散キャッシュ: 分散クラスター アーキテクチャでは、ユーザー セッション情報などのキャッシュをメモリに保存するときに、情報のこの部分を他のマシンと共有する必要があるため、多くの問題が発生します。現時点では、Redis を使用することが良い場合があります。ソリューション 組織間のデータ共有の問題、キャッシュは Redis で最も一般的に使用されるシナリオでもあります
  • 分散ロック: 同時実行性が高い場合、同時実行によるダーティデータを防ぐためにロックが必要です。Java に付属のロック機構は明らかにプロセス間の同時実行には適していません。現時点では、Redis のシングルスレッド機能を使用します。 , 分散ロック制御を実装する
  • インターフェイス電流制限: クラスター環境では、Redis の分散自己インクリメント ID 機能を使用して、指定された時間内の各インターフェイスのリクエスト数を正確にカウントできます。この機能を使用すると、ターゲット内のインターフェイスに対する悪意のある頻繁なブラッシングを制限できます。マナー

もちろん、Redis には非常に多くの使用シナリオがあるだけでなく、パブリッシュ/サブスクライブ、配布ロックの収集など、リストされていないシナリオも多数あります。

実際、マイクロサービス プロジェクトのほとんどは、迅速な開発のために SpringBoot フレームワークに基づいていますが、SpringBoot プロジェクトで Redis をどのように使用すればよいでしょうか? コードの練習は以下の通りです。

1. 開発環境

  • イデア:2021.3.3
  • JDK:1.8
  • スプリングブーツ:2.7.14
  • メイブン:3.6.3

プログラムを通じて Redis に直接接続することはできません。接続するにはクライアント ツールを使用する必要があります。一般的に使用されるものは、Jedis と Lettuce の 2 つです。

springboot 1.5.x バージョンのデフォルトの Redis クライアントは Jedis によって実装され、springboot 2.x バージョンのデフォルトのクライアントは lettuce によって実装されます。

Lettuceと はどちらも Redis に接続されているクライアントですJedis、両者の違いは何でしょうか?

  • Jedisの実装はRedis サーバーに直接接続されているため、接続プールを使用して各 Redis インスタンスに物理接続を追加しない限り、マルチスレッド環境ではスレッドセーフではありません。
  • Lettuceはスケーラブルでスレッドセーフな完全にノンブロッキングの Redis クライアントです。複数のスレッドで RedisConnection を共有できます。Netty NIO フレームワークを使用して複数の接続を効率的に管理し、非同期および同期のデータ アクセス メソッドを提供します。ノンブロッキング リアクティブの構築用アプリケーション

2. コード戦闘

SpringBoot が Redis を統合する場合、ここで使用するのは次のとおりですLettuce

2.1 デフォルトではレタスが使用されます

1. 依存関係を導入します。

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

2. 構成を追加します。

spring:
  redis:
    host: localhost
    port: 6379
    password:
    timeout: 2000s
    # 配置文件中添加 lettuce.pool 相关配置,则会使用到lettuce连接池
    lettuce:
      pool:
        max-active: 8  # 连接池最大连接数(使用负值表示没有限制) 默认为8
        max-wait: -1ms # 接池最大阻塞等待时间(使用负值表示没有限制) 默认为-1ms
        max-idle: 8    # 连接池中的最大空闲连接 默认为8
        min-idle: 0    # 连接池中的最小空闲连接 默认为 0

2.2 ジェダイへの変更

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <exclusions>
        <exclusion>
            <groupId>io.lettuce</groupId>
            <artifactId>lettuce-core</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
</dependency>

jedis依存関係が導入されcommons-pool2ない場合は、導入されます。

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>

構成を追加します。

spring:
  redis:
    host: localhost
    port: 6379
    password:
    timeout: 2000s
    # 配置文件中添加 jedis.pool 相关配置,则会使用到 jedis 连接池
    jedis:
      pool:
        max-active: 10
        max-idle: 8
        min-idle: 0
        max-wait: 60s

2.3 RedisTemplate オブジェクトを使用して Redis を操作する

SpringBootではRedisを操作するためにRedisTemplateオブジェクトを使用します。

Springboot の自動構成原理には、次の 2 つの側面が関係します。

  1. SpringBoot のすべての構成クラスには自動構成クラスがあります。Redis自動構成
  2. 自動構成クラスは、構成ファイルのプロパティにバインドされます。Redis のプロパティ

RedisAutoConfiguration.class

public class RedisAutoConfiguration {
    
    
    public RedisAutoConfiguration() {
    
    
    }

    @Bean
    @ConditionalOnMissingBean(name = {
    
    "redisTemplate"})
    @ConditionalOnSingleCandidate(RedisConnectionFactory.class)
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
    
    
        RedisTemplate<Object, Object> template = new RedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnSingleCandidate(RedisConnectionFactory.class)
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
    
    
        return new StringRedisTemplate(redisConnectionFactory);
    }
}

StringRedisTemplate

public class StringRedisTemplate extends RedisTemplate<String, String> {
    
    
    public StringRedisTemplate() {
    
    
        this.setKeySerializer(RedisSerializer.string());
        this.setValueSerializer(RedisSerializer.string());
        this.setHashKeySerializer(RedisSerializer.string());
        this.setHashValueSerializer(RedisSerializer.string());
    }

    public StringRedisTemplate(RedisConnectionFactory connectionFactory) {
    
    
        this();
        this.setConnectionFactory(connectionFactory);
        this.afterPropertiesSet();
    }

    protected RedisConnection preProcessConnection(RedisConnection connection, boolean existingConnection) {
    
    
        return new DefaultStringRedisConnection(connection);
    }
}

上記から、2 種類のRedisTemplateオブジェクトが挿入されます。

  1. redisTemplateという名前の RedisTemplate オブジェクトが挿入されていない場合は、RedisTemplate<Object, Object>そのオブジェクトが挿入されます
  2. オブジェクトを注入しますStringRedisTemplateそしてStringRedisTemplateオブジェクトはRedisTemplate<String, String>クラスを継承します

RedisTemplateRedis を操作するには、上記 2 種類のオブジェクトを使用します。

@RestController
@RequestMapping("/redis")
public class RedisController {
    
    

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    @GetMapping("/set")
    public String set() {
    
    
        stringRedisTemplate.opsForValue().set("name", "zzc");
        redisTemplate.opsForValue().set("age", "zzc");
        return "set";
    }
}

呼び出しが成功したら、Redis クライアント ツールを使用して以下を表示します。

ここに画像の説明を挿入します
発見する:

redisTemplate.opsForValue().set("age", "zzc");keyすべての操作がvalue意味不明になります。

springbootシリーズ - redisTemplateとstringRedisTemplateの比較、redisTemplateのいくつかのシリアル化メソッドの比較

デバッグ ソース コードから、RedisTemplate<Object, Object>キーと値のシリアル化がデフォルトで行われJdkSerializationRedisSerializer、シリアル化メソッドが次のとおりであることがわかります。

default byte[] serializeToByteArray(T object) throws IOException {
    
    
   ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
   this.serialize(object, out);
   return out.toByteArray();
}

public void serialize(Object object, OutputStream outputStream) throws IOException {
    
    
    if (!(object instanceof Serializable)) {
    
    
        throw new IllegalArgumentException(this.getClass().getSimpleName() + " requires a Serializable payload but received an object of type [" + object.getClass().getName() + "]");
    } else {
    
    
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
        objectOutputStream.writeObject(object);
        objectOutputStream.flush();
    }
}

キーと値をバイト型にシリアル化すると文字化けしてしまいます。(可読性が悪い)

そしてStringRedisTemplateオブジェクトはRedisSerializer次のシーケンスを使用します

2.4 カスタム RedisTemplate オブジェクト

StringRedisTemplate読みやすくするためにクラスを使用できますが、キーと値の両方が String 型である必要があるという要件があります。

しかし問題があり、私たちは普段たくさんのオブジェクトを使用するので、オブジェクトをどのように保管するか?

たとえば、User オブジェクトは次のとおりです。

public class User {
    
    
    private String id;
    private String userName;
    private Integer age;
    // getter/setter
}

RedisTemplate<String, String> のジェネリック パラメーターはすべて String 型であるため、Java オブジェクトを String オブジェクトに変換するだけで済みます。

@Override
public boolean addUser(User user) {
    
    
   redisTemplate.opsForValue().set("user", JSON.toJSONString(user));
   String strUser = redisTemplate.opsForValue().get("user1");
   User resultUser = JSON.parseObject(strUser, User.class);
   return true;
}

Redis に保存する前に Java オブジェクトを Json 文字列に変換し、読み取り後に Json 文字列を Java オブジェクトに変換します。

これは確かに実現可能ですが、格納するオブジェクトが多数ある場合、Java オブジェクトを Json 文字列に繰り返し変換する必要があるのではないでしょうか。これは非常に複雑ではありませんか?

引き続きRedisAutoConfiguration.classソース コードを確認すると、挿入されたコードがアノテーションRedisTemplate<Object, Object>によって変更されていることがわかります@ConditionalOnMissingBean(name="redisTemplate")。 Spring コンテナーにオブジェクトがある場合RedisTemplate、自動的に構成された RedisTemplate はインスタンス化されません。したがって、構成クラスを自分で直接記述して RedisTemplate を構成できます。さらに、キーは String 型で、値は Object 型 (String、int、object など) であることを推奨します。

@Configuration
public class RedisConfig {
    
    

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
    
    
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);

        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        // json 序列化配置
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        // String 序列化
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // 所有的 key 采用 string 的序列化
        template.setKeySerializer(stringRedisSerializer);
        // 所有的 value 采用 jackson 的序列化
        template.setValueSerializer(jackson2JsonRedisSerializer);
        // hash 的 key 采用 string 的序列化
        template.setHashKeySerializer(stringRedisSerializer);
        // hash 的 value 采用 jackson 的序列化
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }
}

テスト:

@RestController
@RequestMapping("/redis")
public class RedisController {
    
    

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @GetMapping("/set")
    public String set() {
    
    
        User user = new User();
        user.setName("zzc");
        user.setAge(18);
        redisTemplate.opsForValue().set("user", user);
        return "set";
    }

}

2.5 RedisUtil ツールクラス

@Component
public class RedisUtil {
    
    

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;


    // ============================Common=============================
    
    public void setHashValueSerializer(RedisSerializer serializer) {
    
    
        redisTemplate.setHashValueSerializer(serializer);
    }

    /**
     * 指定缓存失效时间
     *
     * @author zzc
     * @date 2023/8/2 11:06
     * @param key    键
     * @param time   时间(秒)
     * @return boolean
     */
    public boolean expire(String key, long time) {
    
    
        try {
    
    
            if (time > 0) {
    
    
                redisTemplate.expire(key, time, TimeUnit.SECONDS);
            }
            return true;
        } catch (Exception e) {
    
    
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 根据key 获取过期时间
     *
     * @author zzc
     * @date 2023/8/2 11:07
     * @param key    键 不能为null
     * @return long  时间(秒) 返回0代表为永久有效
     */
    public Long getExpire(String key) {
    
    
        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
    }

    /**
     * 判断key是否存在
     *
     * @author zzc
     * @date 2023/8/2 11:07
     * @param key      键
     * @return boolean 存在 false不存在
     */
    public boolean hasKey(String key) {
    
    
        try {
    
    
            return Boolean.TRUE.equals(redisTemplate.hasKey(key));
        } catch (Exception e) {
    
    
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 删除缓存
     *
     * @author zzc
     * @date 2023/8/2 11:08
     * @param key   可以传一个值 或多个
     */
    @SuppressWarnings("unchecked")
    public void del(String... key) {
    
    
        if (key != null && key.length > 0) {
    
    
            if (key.length == 1) {
    
    
                redisTemplate.delete(key[0]);
            } else {
    
    
                //springboot2.4后用法
                redisTemplate.delete(Arrays.asList(key));
            }
        }
    }

    /**
     * 获取指定前缀的一系列key
     * 使用scan命令代替keys, Redis是单线程处理,keys命令在KEY数量较多时,
     * 操作效率极低【时间复杂度为O(N)】,该命令一旦执行会严重阻塞线上其它命令的正常请求
     *
     * @author zzc
     * @date 2023/8/2 11:53
     * @param keyPrefix
     * @return java.util.Set<java.lang.String>
     */
    public Set<String> keys(String keyPrefix) {
    
    
        String realKey = keyPrefix + "*";
        try {
    
    
            return redisTemplate.execute((RedisCallback<Set<String>>) connection -> {
    
    
                Set<String> binaryKeys = new HashSet<>();
                //springboot2.4后用法
                Cursor<byte[]> cursor = connection.scan(ScanOptions.scanOptions().match(realKey).count(Integer.MAX_VALUE).build());
                while (cursor.hasNext()) {
    
    
                    binaryKeys.add(new String(cursor.next()));
                }

                return binaryKeys;
            });
        } catch (Throwable e) {
    
    
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 删除指定前缀的一系列key
     *
     * @author zzc
     * @date 2023/8/2 11:53
     * @param keyPrefix
     */
    public void removeAll(String keyPrefix) {
    
    
        try {
    
    
            Set<String> keys = keys(keyPrefix);
            redisTemplate.delete(keys);
        } catch (Throwable e) {
    
    
            e.printStackTrace();
        }
    }
    
    // 执行 lua 脚本
    public <T> T execute(RedisScript<T> script, List<String> keys, Object... args) {
    
    
        return redisTemplate.execute(script, keys, args);
    }

    public boolean convertAndSend(String channel, Object message) {
    
    
        if (!StringUtils.hasText(channel)) {
    
    
            return false;
        }
        try {
    
    
            redisTemplate.convertAndSend(channel, message);
            return true;
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
        return false;
    }


    // ============================String=============================

    /**
     * 普通缓存获取
     *
     * @author zzc
     * @date 2023/8/2 11:08
     * @param key                   键
     * @return java.lang.Object     值
     */
    public Object get(String key) {
    
    
        return key == null ? null : redisTemplate.opsForValue().get(key);
    }

    /**
     * 普通缓存放入
     * @author zzc
     * @date 2023/8/2 11:09
     * @param key           键
     * @param value         值
     * @return boolean      true成功 false失败
     */
    public boolean set(String key, Object value) {
    
    
        try {
    
    
            redisTemplate.opsForValue().set(key, value);
            return true;
        } catch (Exception e) {
    
    
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 普通缓存放入并设置过期时间
     *
     * @author zzc
     * @date 2023/8/2 11:09
     * @param key     键
     * @param value   值
     * @param time    时间(秒) time要大于0 如果time小于等于0 将设置无限期
     * @return boolean  true成功 false 失败
     */
    public boolean set(String key, Object value, long time) {
    
    
        try {
    
    
            if (time > 0) {
    
    
                redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
            } else {
    
    
                set(key, value);
            }
            return true;
        } catch (Exception e) {
    
    
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 递增
     * @author zzc
     * @date 2023/8/2 11:10
     * @param key         键
     * @param delta       要增加几(大于0)
     * @return java.lang.Long
     */
    public Long incr(String key, long delta) {
    
    
        if (delta < 0) {
    
    
            throw new RuntimeException("递增因子必须大于0");
        }
        return redisTemplate.opsForValue().increment(key, delta);
    }

    /**
     * 递减
     *
     * @author zzc
     * @date 2023/8/2 11:11
     * @param key                 键
     * @param delta               要减少几(小于0)
     * @return java.lang.Long
     */
    public Long decr(String key, long delta) {
    
    
        if (delta < 0) {
    
    
            throw new RuntimeException("递减因子必须大于0");
        }
        return redisTemplate.opsForValue().increment(key, -delta);
    }

    public boolean setNx(String key, Object value) {
    
    
        return Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(key, value));
    }
    
    public boolean setNx(String key, Object value, long time) {
    
    
        return Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(key, value, time, TimeUnit.SECONDS));
    }
    
    public void multiSet(Map<String, Object> map) {
    
    
        redisTemplate.opsForValue().multiSet(map);
    }

    public List<Object> multiGet(List<String> keys) {
    
    
        return redisTemplate.opsForValue().multiGet(keys);
    }


    // ================================Hash=================================

    /**
     * Hash Get
     * @author zzc
     * @date 2023/8/2 11:12
     * @param key                键 不能为null
     * @param item               项 不能为null
     * @return java.lang.Object
     */
    public Object hget(String key, String item) {
    
    
        return redisTemplate.opsForHash().get(key, item);
    }

    /**
     * 获取Key对应的所有键值
     *
     * @author zzc
     * @date 2023/8/2 11:12
     * @param key                                                  键
     * @return java.util.Map<java.lang.Object,java.lang.Object>    对应的多个键值
     */
    public Map<Object, Object> hmget(String key) {
    
    
        return redisTemplate.opsForHash().entries(key);
    }

    /**
     * Hash Set
     *
     * @author zzc
     * @date 2023/8/2 11:13
     * @param key         键
     * @param map         对应多个键值
     * @return boolean    true 成功 false 失败
     */
    public boolean hmset(String key, Map<String, Object> map) {
    
    
        try {
    
    
            redisTemplate.opsForHash().putAll(key, map);
            return true;
        } catch (Exception e) {
    
    
            e.printStackTrace();
            return false;
        }
    }

    /**
     * Hash Set 并设置过期时间
     * @author zzc
     * @date 2023/8/2 11:13
     * @param key        键
     * @param map        对应多个键值
     * @param time       时间(秒)
     * @return boolean   true成功 false失败
     */
    public boolean hmset(String key, Map<String, Object> map, long time) {
    
    
        try {
    
    
            redisTemplate.opsForHash().putAll(key, map);
            if (time > 0) {
    
    
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
    
    
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 向一张hash表中放入数据,如果不存在将创建
     *
     * @param key   键
     * @param item  项
     * @param value 值
     * @return true 成功 false失败
     */
    public boolean hset(String key, String item, Object value) {
    
    
        try {
    
    
            redisTemplate.opsForHash().put(key, item, value);
            return true;
        } catch (Exception e) {
    
    
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 向一张hash表中放入数据,如果不存在将创建
     *
     * @param key   键
     * @param item  项
     * @param value 值
     * @param time  时间(秒) 注意:如果已存在的hash表有过期时间,这里将会替换原有的过期时间
     * @return true 成功 false失败
     */
    public boolean hset(String key, String item, Object value, long time) {
    
    
        try {
    
    
            redisTemplate.opsForHash().put(key, item, value);
            if (time > 0) {
    
    
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
    
    
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 删除hash表中的项
     *
     * @author zzc
     * @date 2023/8/2 11:38
     * @param key   键 不能为null
     * @param item  项 可以使多个 不能为null
     */
    public void hdel(String key, Object... item) {
    
    
        redisTemplate.opsForHash().delete(key, item);
    }

    /**
     * 判断 hash 表中是否有该项的值
     *
     * @author zzc
     * @date 2023/8/2 11:38
     * @param key    键 不能为null
     * @param item   项 不能为null
     * @return boolean  true 存在 false不存在
     */
    public boolean hHasKey(String key, String item) {
    
    
        return redisTemplate.opsForHash().hasKey(key, item);
    }

    /**
     * hash 递增 如果不存在,就会创建一个 并把新增后的值返回
     *
     * @author zzc
     * @date 2023/8/2 11:40
     * @param key    键
     * @param item   项
     * @param by     要增加几(大于0)
     * @return double
     */
    public double hincr(String key, String item, double by) {
    
    
        return redisTemplate.opsForHash().increment(key, item, by);
    }

    public Long hincr(String key, String item, long by) {
    
    
        return redisTemplate.opsForHash().increment(key, item, by);
    }

    /**
     * hash 递减
     *
     * @author zzc
     * @date 2023/8/2 11:40
     * @param key    键
     * @param item   项
     * @param by     要减少几(小于0)
     * @return double
     */
    public double hdecr(String key, String item, double by) {
    
    
        return redisTemplate.opsForHash().increment(key, item, -by);
    }

    public List<Object> hmultiGet(String key, List<Object> items) {
    
    
        return redisTemplate.opsForHash().multiGet(key, items);
    }


    // ============================set=============================

    /**
     * 根据key获取Set中的所有值
     *
     * @author zzc
     * @date 2023/8/2 11:41
     * @param key
     * @return java.util.Set<java.lang.Object>
     */
    public Set<Object> sGet(String key) {
    
    
        try {
    
    
            return redisTemplate.opsForSet().members(key);
        } catch (Exception e) {
    
    
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 根据value从一个set中查询,是否存在
     *
     * @author zzc
     * @date 2023/8/2 11:41
     * @param key       键
     * @param value     值
     * @return boolean  true 存在 false不存在
     */
    public boolean sHasKey(String key, Object value) {
    
    
        try {
    
    
            return Boolean.TRUE.equals(redisTemplate.opsForSet().isMember(key, value));
        } catch (Exception e) {
    
    
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 将数据放入set缓存
     *
     * @author zzc
     * @date 2023/8/2 11:42
     * @param key       键
     * @param values    值 可以是多个
     * @return long     成功个数
     */
    public Long sSet(String key, Object... values) {
    
    
        try {
    
    
            return redisTemplate.opsForSet().add(key, values);
        } catch (Exception e) {
    
    
            e.printStackTrace();
            return 0L;
        }
    }

    /**
     * 将 set 数据放入缓存
     *
     * @author zzc
     * @date 2023/8/2 11:42
     * @param key     键
     * @param time    时间(秒)
     * @param values  值 可以是多个
     * @return long   成功个数
     */
    public Long sSetAndTime(String key, long time, Object... values) {
    
    
        try {
    
    
            Long count = redisTemplate.opsForSet().add(key, values);
            if (time > 0) {
    
    
                expire(key, time);
            }
            return count;
        } catch (Exception e) {
    
    
            e.printStackTrace();
            return 0L;
        }
    }

    /**
     * 获取set缓存的长度
     *
     * @author zzc
     * @date 2023/8/2 11:45
     * @param key
     * @return long
     */
    public Long sGetSetSize(String key) {
    
    
        try {
    
    
            return redisTemplate.opsForSet().size(key);
        } catch (Exception e) {
    
    
            e.printStackTrace();
            return 0L;
        }
    }

    /**
     * 移除值为value的
     *
     * @author zzc
     * @date 2023/8/2 11:45
     * @param key    键
     * @param values 值 可以是多个
     * @return long  移除的个数
     */
    public Long setRemove(String key, Object... values) {
    
    
        try {
    
    
            return redisTemplate.opsForSet().remove(key, values);
        } catch (Exception e) {
    
    
            e.printStackTrace();
            return 0L;
        }
    }


    // ===============================List=================================

    /**
     * 获取list缓存的内容
     *
     * @author zzc
     * @date 2023/8/2 11:46
     * @param key      键
     * @param start    开始
     * @param end      结束 0 到 -1代表所有值
     * @return java.util.List<java.lang.Object>
     */
    public List<Object> lGet(String key, long start, long end) {
    
    
        try {
    
    
            return redisTemplate.opsForList().range(key, start, end);
        } catch (Exception e) {
    
    
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 获取list缓存的长度
     *
     * @author zzc
     * @date 2023/8/2 11:47
     * @param key
     * @return long
     */
    public Long lGetListSize(String key) {
    
    
        try {
    
    
            return redisTemplate.opsForList().size(key);
        } catch (Exception e) {
    
    
            e.printStackTrace();
            return 0L;
        }
    }

    /**
     * 通过索引 获取list中的值
     *
     * @author zzc
     * @date 2023/8/2 11:47
     * @param key     键
     * @param index   索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
     * @return java.lang.Object
     */
    public Object lGetIndex(String key, long index) {
    
    
        try {
    
    
            return redisTemplate.opsForList().index(key, index);
        } catch (Exception e) {
    
    
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 将list放入缓存
     * @author zzc
     * @date 2023/8/2 11:48
     * @param key       键
     * @param value     值
     * @return boolean
     */
    public boolean lSet(String key, Object value) {
    
    
        try {
    
    
            redisTemplate.opsForList().rightPush(key, value);
            return true;
        } catch (Exception e) {
    
    
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 将list放入缓存
     * @author zzc
     * @date 2023/8/2 11:48
     * @param key       键
     * @param value     值
     * @param time  时间(秒)
     * @return boolean
     */
    public boolean lSet(String key, Object value, long time) {
    
    
        try {
    
    
            redisTemplate.opsForList().rightPush(key, value);
            if (time > 0) {
    
    
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
    
    
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 将list放入缓存
     *
     * @author zzc
     * @date 2023/8/2 11:49
     * @param key        键
     * @param value      值
     * @return boolean   时间(秒)
     */
    public boolean lSet(String key, List<Object> value) {
    
    
        try {
    
    
            redisTemplate.opsForList().rightPushAll(key, value);
            return true;
        } catch (Exception e) {
    
    
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 将list放入缓存
     *
     * @author zzc
     * @date 2023/8/2 11:49
     * @param key        键
     * @param value      值
     * @param time       时间(秒)
     * @return boolean
     */
    public boolean lSet(String key, List<Object> value, long time) {
    
    
        try {
    
    
            redisTemplate.opsForList().rightPushAll(key, value);
            if (time > 0) {
    
    
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
    
    
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 根据索引修改list中的某条数据
     *
     * @author zzc
     * @date 2023/8/2 11:51
     * @param key     键
     * @param index   索引
     * @param value   值
     * @return boolean
     */
    public boolean lUpdateIndex(String key, long index, Object value) {
    
    
        try {
    
    
            redisTemplate.opsForList().set(key, index, value);
            return true;
        } catch (Exception e) {
    
    
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 移除N个值为value
     *
     * @author zzc
     * @date 2023/8/2 11:51
     * @param key    键
     * @param count  移除多少个
     * @param value  值
     * @return long  移除的个数
     */
    public Long lRemove(String key, long count, Object value) {
    
    
        try {
    
    
            return redisTemplate.opsForList().remove(key, count, value);
        } catch (Exception e) {
    
    
            e.printStackTrace();
            return 0L;
        }
    }

}

おすすめ

転載: blog.csdn.net/sco5282/article/details/132186325