Redis アプリケーション (8) - Redis プロジェクト アプリケーション: SpringBoot と組み合わせて Redis にオブジェクトを保存する方法、RedisUtil ツール クラスのカプセル化、および発生した問題

ここに画像の説明を挿入します

序文

Redis は優れたオープンソースで効率的なインメモリ データベースとして、さまざまなプロジェクトで使用されており、Redis を使いこなすことはプログラマーにとって必要なスキルの 1 つです。このブログ シリーズでは、アプリケーション シナリオを組み合わせて、Redis のインストールから使用、入門から上級までの関連コンテンツを説明します。

このブログでは、Spring プロジェクトの Redis に Java オブジェクトを格納する方法と、使用中に発生する問題を紹介します。

その他の関連する Redis ブログは次のとおりです。

Redis とは何か、Docker の Redis のインストール、Redis の基本データ型 + 共通コマンド、SpringBoot の Redis の事前統合

ここに画像の説明を挿入します
redis.conf 構成ファイルと組み合わせることで、Redis の 2 つのデータ永続化ソリューション、RDB と AOF について深く理解できます。

ここに画像の説明を挿入します

Redis データ永続性 & CAP 分散理論 (高可用性) & Redis マスター/スレーブ構築 & Redis センチネル メカニズム

ここに画像の説明を挿入します

Linux 上の Docker コンテナ Redis に基づいて 1 つのマスター、2 つのスレーブ、3 つのセンチネルを構築し、Redis センチネルを SpringBoot と統合します

ここに画像の説明を挿入します

Redis の不正アクセスの脆弱性と脆弱性の部分的な再発を理解し、接続パスワードを設定し、他の Redis コマンドを学習する

ここに画像の説明を挿入します

Redis プロジェクト アプリケーション (1): 検証コード -> UUID から Snowflake ID と JMeter の高同時実行テストとダウンロード、インストール、使用

ここに画像の説明を挿入します

Redis プロジェクト アプリケーション (2): 書籍の購入ラッシュ -> Redis の同時実行性の高さの問題と分散ロックの使用 Redission

ここに画像の説明を挿入します
Redis プロジェクト アプリケーション (3): Bookrush 2.0 —> Lua スクリプト & Redis+Lua+Redission でラッシュ購入 & Redission ロックを実現

ここに画像の説明を挿入します

Redisプロジェクト応用(4):キャッシュ予熱、ユーザー登録を例に→登録処理とキャッシュ予熱方法、quartz方式/@Schedule方式

ここに画像の説明を挿入します
Redis プロジェクト アプリケーション (5): キャッシュ自動更新 -> Canal パイプライン & MySQL 設定 + Canal のインストール & エントリー ケース & Canal プロジェクト アプリケーション

ここに画像の説明を挿入します
Redisプロジェクト応用⑥:ブルームフィルター - ホワイトリスト ----> Reidの問題、雪崩・故障・侵入【重要】&ブルームフィルター

ここに画像の説明を挿入します

Redis データの一貫性 & Java コードを使用したロックによる一貫性の解決 & lua スクリプトの使用によるマイナス 1 のアトミック性の達成 & setnex ロックと分散環境におけるその問題 & Redission フレームワークの使用

ここに画像の説明を挿入します

IDEA が 2 つの Tomcat サービスを開始し、リバース プロキシに nginx を使用し、JMeter が分散状況での同期ロックの失敗をテストする方法

ここに画像の説明を挿入します

導き出す


1. これまでの Redis 関連ブログのまとめ;
2. Java オブジェクトを Redis に保存するための解決策;
3. 実際に使用する際に遭遇した問題とその解決策; 5. Redis に Javaオブジェクトを格納するための解決策

JavaオブジェクトをRedisに保存する方法

1. この記事のプロジェクトの依存関係

最も基本的な springboot redis 依存関係の使用

コードではブルーム フィルターが使用されているため、ここでは hutool ツール パッケージを参照します。

        <!--        redis的依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

<!--        hutool工具包-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.11</version>
        </dependency>

2. コア構成クラス

中心となるのは、保存されたオブジェクトの Redistemplate 構成です。

これには、Redisson 構成と Lua スクリプト構成も含まれます。

package com.tianju.fresh.config;

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.springframework.context.annotation.Bean;
import org.redisson.config.Config;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;


/**
 * Redisson的配置,lua脚本的配置,redis序列化存对象的配置
 */
@Configuration
public class RedisConfig {
    
    

    /**
     * Redisson的配置,
     * Redisson框架,分布式环境下redis数据一致性
     * @return
     */
    @Bean
    public RedissonClient redissonClient(){
    
    
        Config config = new Config();
        config.useSingleServer().setAddress("redis://127.0.0.1:6379")
                .setPassword("5672");
        return Redisson.create(config);
    }

    /**
     * lua脚本的配置类,让减库存-1操作原子化
     * @return
     */
    @Bean
    public RedisScript<Long> redisScript(){
    
    
        DefaultRedisScript redisScript = new DefaultRedisScript<>();
        redisScript.setResultType(Long.class);
        // lua脚本的位置
        redisScript.setLocation(
                new ClassPathResource("/lua/goods-unstock.lua") // 关联lua脚本
        );
        return redisScript;
    }

    /**
     * redis序列化的相关配置,可以存对象
     * @return
     */
    @Bean
    public RedisTemplate redisTemplateInit(RedisConnectionFactory redisConnectionFactory) {
    
    

        RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();

        redisTemplate.setConnectionFactory(redisConnectionFactory);
        //设置序列化Key的实例化对象
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        //设置序列化Value的实例化对象
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        /**
         *
         * 设置Hash类型存储时,对象序列化报错解决
         */
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        return redisTemplate;
    }

}

3. RedisUtil ツールクラスをカプセル化する

Redis の実際のアプリケーションで形成されるカスタム Redis ツール クラスは、主に Redistemplate と StringRedistemplate の依存関係を挿入し、これら 2 つのメソッドを呼び出します。

このうち Redistemplate は Java オブジェクトの格納に使用され、StringRedistemplate は通常の操作に使用されます。

package com.tianju.fresh.util;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Set;
import java.util.concurrent.TimeUnit;


@Component
public class RedisUtil {
    
    
    @Autowired
    private RedisTemplate<String,Object> redisTemplate;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    public void  saveObjectToRedis(String key,Object json){
    
    
        redisTemplate.opsForValue().set(key,json);
    }

    /**
     * 从redis里面获取json对象,如果没有,返回null
     * @param key
     * @return
     */
    public Object getJsonFromRedis(String key){
    
    
        return redisTemplate.opsForValue().get(key);
    }

    /**
     * 删除redis里面的值,键
     * @param key 删除的键
     * @return
     */
    public Boolean deleteKey(String key){
    
    
        return redisTemplate.delete(key);
    }

    /**
     * 存到Redis里面的 set 中
     * @param key 存的键
     * @param value 存到set的值
     */
    public void saveSetToRedis(String key,String... value){
    
    
        for (String s:value){
    
    
            if (s!=null && !s.equals("")){
    
    
                stringRedisTemplate.opsForSet().add(key, s);
            }
        }
    }

    /**
     * 判断是否在redis的set中
     * @param key
     * @param val
     * @return
     */
    public Boolean isInSet(String key,String val){
    
    
        return stringRedisTemplate.opsForSet().isMember(key, val);
    }

    /**
     * 获得set中的值
     * @param key 键
     * @return
     */
    public Set<String> getSet(String key){
    
    
        return stringRedisTemplate.opsForSet().members(key);
    }

    /**
     * 从redis里面的set删除数据
     * @param key
     * @param val
     */
    public void removeFromSet(String key,String val){
    
    
        stringRedisTemplate.opsForSet().remove(key, val);
    }



    /**
     * 获得存到redis里面的键对应的string类型的值
     * @param key 键
     * @return
     */
    public String getStringValue(String key){
    
    
        return stringRedisTemplate.opsForValue().get(key);
    }

    /**
     * 保存到redis里面string
     * @param key
     * @param timeout 过期时间,传的是多少s之后过期
     * @param val
     */
    public void saveStringValue(String key,String val,Integer... timeout){
    
    
        if (timeout==null){
    
    
            stringRedisTemplate.opsForValue().set(key,val);
        }else {
    
    
            stringRedisTemplate.opsForValue().set(key,val,timeout[0], TimeUnit.SECONDS);
        }
    }

    /**
     * 看某个键是否存在于Redis中
     * @param key 待检验的键
     * @return
     */
    public Boolean isKeyInRedis(String key){
    
    
        return stringRedisTemplate.hasKey(key);
    }

}

4. ツールの使用

以下にキャッシュ予熱コードを例に挙げますが、ツールクラスを使用する場合は依存性注入を使用し、ツールクラスのメソッドを呼び出します。

package com.tianju.fresh.autho.bloomFilter;

import com.tianju.fresh.entity.Customer;
import com.tianju.fresh.mapper.CustomerMapper;
import com.tianju.fresh.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 将用户名,手机号码,邮箱存到redis里面,
 * 作用:
 * 1.登陆的时候先到redis里面查询;
 * 2.用户注册的时候先从redis里面看用户名是否重复
 */
@Component
@Slf4j
public class LoginKeyPreHot {
    
    

    private final String LOGIN_KEY = "loginKey";

    @Autowired
    private CustomerMapper customerMapper;

    @Autowired
    private RedisUtil redisUtil;

    /**
     * 每天半夜 2点 跟新布隆过滤器和缓存
     */
    @Scheduled(cron = "0 0 2 * * ?")
    public void perHot(){
    
    
        // 1.先清除缓存中的数据
        // 2.然后更新一下redis里面的loginKey;
        // 3.同时把loginKey放到布隆过滤器中

        redisUtil.deleteKey(LOGIN_KEY); // 删除redis里面的key

        Set set = new HashSet();
        List<Customer> customers = customerMapper.selectList(null);

        customers.forEach(c->{
    
    
            // 更新Redis里面的set
            redisUtil.saveSetToRedis(LOGIN_KEY, c.getUsername(),c.getEmail(),c.getContactTel());
            // 更新布隆过滤器
            BloomFilterUtil.addBloom(c.getUsername(),c.getEmail(),c.getContactTel());
            // 记录一下谁进了布隆过滤器中
            set.add(c.getUsername());
            set.add(c.getContactTel());
            set.add(c.getEmail());
        });

        // TODO:手动在布隆过滤器中放一个Arya, 模拟骗过了布隆过滤器,但没有骗过redis的情况
        BloomFilterUtil.addBloom("Arya");

        log.debug("缓存预热 + 布隆过滤器初始化成功 >>>" +set);
    }
}

実際のアプリケーションで遭遇するバグ

1.問題の説明

Redis を保存するときに Java オブジェクトのシリアル化を実装する Redistemplate を使用している場合、現時点では SREM コマンドを使用してそれを削除することはできません。

ここに画像の説明を挿入します

2.問題解決

stringRedisTemplateを使用して保存するだけです

ここに画像の説明を挿入します


要約する

1. これまでの Redis 関連ブログのまとめ;
2. Java オブジェクトを Redis に保存するための解決策;
3. 実際に使用する際に遭遇した問題とその解決策; 5. Redis に Javaオブジェクトを格納するための解決策

おすすめ

転載: blog.csdn.net/Pireley/article/details/133181043