Spring BootでのLettuceを用いたRedis統合ガイド

一、Lettuceについて

Redisサーバーについては、以前のブログ記事で既に触れていますので、ここでは詳細を割愛します。LettuceとJedisは両方ともRedisサーバーに接続するクライアントプログラムですが、実装方法が異なります。JedisはRedisサーバーに直接接続しますが、マルチスレッド環境ではスレッドセーフではないため、接続プールを使用する必要があります。各Jedisインスタンスはスレッド間の同時アクセスに対応し、スレッドセーフであり、マルチスレッド環境での同時アクセスを満たします。また、スケーラブルな設計になっており、必要に応じて接続インスタンスを増やすことも可能です。

二、Maven依存関係

従来の手順に従い、まず依存関係をインポートし、次にプロパティを設定し、最後にインスタンスを作成します。Spring Bootを使用する場合、基本的な手順は似ています。

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

三、プロパティ設定

ここではLettuceを使用します。Jedisを使用する場合は、以下の設定で"lettuce"を"jedis"に変更してください。

# Redis接続設定
spring.redis.host=127.0.0.1
spring.redis.password=
spring.redis.port=6379
spring.redis.timeout=1000
spring.redis.database=0

# Lettuce接続プール設定
spring.redis.lettuce.pool.min-idle=0
spring.redis.lettuce.pool.max-idle=8
spring.redis.lettuce.pool.max-wait=-1ms
spring.redis.lettuce.pool.max-active=8

四、実装例

以前のデモプロジェクトをベースに修正します。デフォルトのテンプレートはStringRedisTemplate<String,String>のみをサポートし、文字列のみを保存できます。この場合、カスタムテンプレートを定義する必要があります。カスタムテンプレートを定義した後でも文字列を保存したい場合は、RedisTemplateを使用できます。両者は競合しません。RedisCacheAutoConfigurationではカスタムRedisTemplateが定義されています。

package com.example.config;

import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
@AutoConfigureAfter(RedisAutoConfiguration.class)
public class RedisCacheConfiguration {
    
    @Bean
    public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.setConnectionFactory(connectionFactory);
        return template;
    }
}

Userクラスにコンストラクタを追加します。

package com.example.model;

import java.io.Serializable;

public class UserInfo implements Serializable {
    private static final long serialVersionUID = 1L;
    
    private String id;
    private String name;
    private int age;
    private GenderType gender;
    
    public UserInfo(String id, String name, int age, GenderType gender) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.gender = gender;
    }
    
    public UserInfo() {
        super();
    }
    
    @Override
    public String toString() {
        return "UserInfo [id=" + id + ", name=" + name + ", age=" + age + ", gender=" + gender + "]";
    }
    
    // Getter and Setter methods
    public String getId() {
        return id;
    }
    
    public void setId(String id) {
        this.id = id;
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public int getAge() {
        return age;
    }
    
    public void setAge(int age) {
        this.age = age;
    }
    
    public GenderType getGender() {
        return gender;
    }
    
    public void setGender(GenderType gender) {
        this.gender = gender;
    }
}

enum GenderType {
    MAN, WOMAN
}

View Code以前のデモプロジェクトのUserControllerを修正し、StringRedisTemplateとRedisTemplateを注入してテストします。主な追加コードは39-46行目にあります。

package com.example.controller;

import java.util.List;

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.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.example.model.UserInfo;
import com.example.model.GenderType;
import com.example.mapper.ReadUserMapper;
import com.example.mapper.WriteUserMapper;

@Controller
@RequestMapping("/user")
public class UserController {
    
    @Autowired
    private WriteUserMapper writeUserMapper;
    
    @Autowired
    private ReadUserMapper readUserMapper;
    
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    @RequestMapping(value = "/alluser.do", method = RequestMethod.GET)
    public String getAllUsers(Model model) {
       List<UserInfo> users = readUserMapper.getAllUsers();
       model.addAttribute("users", users);
       
       // String型のデータをRedisに保存
       stringRedisTemplate.opsForValue().set("testKey", "sampleValue");
       String retrievedValue = stringRedisTemplate.opsForValue().get("testKey");
       model.addAttribute("redisValue", retrievedValue);
       
       // UserInfoオブジェクトをRedisに保存
       String userKey = "user1234567890";
       redisTemplate.opsForValue().set(userKey, new UserInfo(userKey, "SampleUser", 25, GenderType.MAN));
       
       // UserInfoオブジェクトをRedisから取得
       UserInfo retrievedUser = (UserInfo) redisTemplate.opsForValue().get(userKey);
       model.addAttribute("userInfo", retrievedUser);
       
       return "userList";
    }
    
    @RequestMapping(value = "/insert.do", method = RequestMethod.GET)
    public String addUser(Model model) {
       UserInfo newUser = new UserInfo();
       newUser.setName("NewUser");
       newUser.setAge(30);    
       writeUserMapper.insert(newUser);
       
       List<UserInfo> users = writeUserMapper.getAllUsers();
       model.addAttribute("users", users);
       return "userList";
    }
}

View CodeURL http://localhost:8080/user/alluser.do を開くと、Redisから取得したString型のキーとUserInfoオブジェクトが確認できます。

五、エラー処理

URLを開いた際にRedis接続タイムアウトのエラー「io.lettuce.core.RedisCommandTimeoutException: Command timed out」が発生しました。最初はタイムアウト値が小さすぎると考え、10000に設定してみましたが、依然としてエラーが発生しました。その後、以前のRedisサーバーの起動方法を確認し、redis.windows.confを使用してredis-server.exe redis.windows.confで起動したところ、問題が解決しました。以前ダブルクリックで起動していたことに問題があったようです。

ここではRedisの基本的な使用例のみを紹介します。実際のプロジェクトでは、クラスタ構成やキャッシュとの連携など、より複雑なシナリオが必要になる場合があります。これらについては後ほど追記していきます。

タグ: Spring Boot redis Lettuce Java NoSQL

7月4日 20:06 投稿