2019年4月23日

Redis Client - 使用Lettuce

Redis是一套基於key-value的in-memory database,常見的用途之一,是拿來作為Application Server的快取系統。
Lettuce則是一個強調thread-safe的Java Redis Client。

Redis參數設定

可以使用XML或Annotation兩種方式,來設定Redis的IP、Port。

方法(一):建立XML設定檔

以下假設專案使用webapp,並將XML檔案放在src/main/resource底下,取名為lettuce.xml

完整XML檔案範例如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<!-- beans settings -->

</beans>

Sentinel設定

若要連線至3個Sentinel:

  • 192.168.1.32:27030
  • 192.168.1.32:27031
  • 192.168.1.32:27032

範例如下:

<bean id="sentinelConfig" class="org.springframework.data.redis.connection.RedisSentinelConfiguration">
    <constructor-arg name="master" value="mymaster" />
    <constructor-arg name="sentinelHostAndPorts">
        <set>
            <value>192.168.1.32:27030</value>
            <value>192.168.1.32:27031</value>
            <value>192.168.1.32:27032</value>
        </set>
    </constructor-arg>
</bean>

Connection設定

Java Redis Client使用lettuce,如下:

<bean id="lettuceConnectionFactory" class="org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory">
    <constructor-arg ref="sentinelConfig" />
</bean>

RedisTemplate設定

    <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" p:connection-factory-ref="lettuceConnectionFactory"  />

方法(二):Annotation

建立一個類別,並於class前加上 @Configuration

//...
import org.springframework.context.annotation.Configuration;
//...

@Configuration
public class SpringDataRedisLettuceConfig {
//...
}

Connection Pool 設定

@Bean
public GenericObjectPoolConfig genericObjectPoolConfig() {
    GenericObjectPoolConfig genericObjectPoolConfig = new GenericObjectPoolConfig();
    genericObjectPoolConfig.setMaxIdle(8);
    genericObjectPoolConfig.setMinIdle(0);
    genericObjectPoolConfig.setMaxTotal(8);
    genericObjectPoolConfig.setMaxWaitMillis(100000);
    return genericObjectPoolConfig;
}

Sentinel設定

若要連線至3個Sentinel:

  • 192.168.1.32:27030
  • 192.168.1.32:27031
  • 192.168.1.32:27032

範例如下:

@Bean
public RedisSentinelConfiguration sentinelConfig()  {
    Set<String> sentinels = new HashSet<>();
    sentinels.add("192.168.1.32:27030");
    sentinels.add("192.168.1.32:27031");
    sentinels.add("192.168.1.32:27032");
    RedisSentinelConfiguration redisSentinelConfiguration = new RedisSentinelConfiguration("mymaster", sentinels);
    return redisSentinelConfiguration;
}

Connection設定

Java Redis Client使用lettuce,如下:

@Bean
public LettuceConnectionFactory lettuceConnectionFactory(RedisSentinelConfiguration sentinelConfig, GenericObjectPoolConfig genericObjectPoolConfig)  {

    LettuceClientConfiguration clientConfig = LettucePoolingClientConfiguration.builder()
            .commandTimeout(Duration.ofMillis(10000))
            .poolConfig(genericObjectPoolConfig)
            .build();

    LettuceConnectionFactory factory = new LettuceConnectionFactory(sentinelConfig, clientConfig);
    return factory;
}

RedisTemplate設定

設定KeySerializer使用StringRedisSerializer

@Bean
RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
    RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
    redisTemplate.setConnectionFactory(lettuceConnectionFactory);
    StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
    redisTemplate.setKeySerializer(stringRedisSerializer);
    redisTemplate.setHashKeySerializer(stringRedisSerializer);
    return redisTemplate;
}

在Java中使用RedisTemplate操作Redis

  • 若剛才使用方法(一):建立XML設定檔

由於XML檔案位於src/main/resource/lettuce.xml,此處先使用ClassPathXmlApplicationContext取得RedisTemplate物件:

ApplicationContext ctx = new ClassPathXmlApplicationContext(new String[] { "lettuce.xml" });
RedisTemplate redisTemplate = ctx.getBean(RedisTemplate.class);

  • 若剛才使用方法(二):Annotation的話,則只要確定Spring的root-context.xml中,有設定掃描相關的package即可:
...
<context:component-scan base-package="tw.com.maxkit.cdc.configuration" />
...

設定KeySerializer

設定KeySerializer為StringRedisSerializer

RedisSerializer<String> stringSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(stringSerializer);

因為無論是Key還是Value,預設都使用JdkSerializationRedisSerializer;如此一來,假設原本程式中寫入的key為mykey,若沒有將KeySerializer為StringRedisSerializer,寫入資料後,進console查看keys資料如下:

192.168.1.32:7030> keys *
1) "\xac\xed\x00\x05t\x00\x05mykey"

若有將KeySerializer為StringRedisSerializer時,寫入資料後,進console查看keys資料如下

192.168.1.32:7030> keys *
1) "mykey"

兩筆資料將會是不同的key,因此KeySerializer應一開始就設定好,並保持一致

此外,Value也可以設定使用StringRedisSerializer:

redisTemplate.setValueSerializer(stringSerializer);

不過,如果需要將序列化的物件存入,那就不應將ValueSerializer設為StringRedisSerializer。

透過Operations操作Redis

ValueOperations

取得ValueOperations物件

ValueOperations<String, String> vops = redisTemplate.opsForValue();

寫入字串

vops.set("vops_key","vops_value");

讀取字串

String vops_value =  vops.get("vops_key");

寫入/讀取物件

如同之前提到,寫入的Value預設是使用JdkSerializationRedisSerializer。因此也可以寫入有implements Serializable的物件

ValueOperations<String, TestUser> vops = redisTemplate.opsForValue();

vops.set("user:001", new TestUser("Allen", 20));

TestUser user001 = vops.get("user:001");

TestUser需implements Serializable,如下:

public class TestUser implements Serializable {
    private String name;
 private int age;
 public TestUser(String name, int age) {
// ...

ListOperations

建立ListOperations物件

ListOperations<String, String> listOp = redisTemplate.opsForList();

寫入list

long result = listOp.leftPush(key, value);

讀取list

List<String> values = lop.range(key, 0, -1);

不難發現,多數函數名稱都與原本的Redis指令很接近;若已熟悉Redis的話,使用Lettuce也能很快就上手。

刪除key

刪除資料時,直接使用redisTemplate的delete即可。

redisTemplate.delete(key)

沒有留言:

張貼留言