Like Share Discussion Bookmark Smile

J.J. Huang   2019-04-10   Spring Boot   瀏覽次數:1773次   DMCA.com Protection Status

SpringBoot - 第二十三章 | Redis的集成和使用(二)

前一章節示範了自動配置的StringRedisTemplate對象進行Redis的讀寫操作,該對像從命名中就可注意到支持的是String類型。有使用過spring-data-redis的一定熟悉RedisTemplate<K, V>接口,StringRedisTemplate就相當於RedisTemplate<String, String>的實作。

除了String類型,開發中我們還經常會在Redis中存儲對象,這時候我們就會想是否可以使用類似RedisTemplate<String, Customer>來初始化並進行操作。但是Spring Boot並不支持直接使用,需要我們自己實作RedisSerializer接口來對傳入對象進行序列化和反序列化,下方會通過一個實例來完成對象的讀寫操作。

Docker Redis準備

1
docker run --name myredis -p 6379:6379 -d redis:3.2 redis-server --appendonly yes

命令說明:

1
2
3
--name myredis:容器取名為myredis
-p 6379:6379 : 將容器的6379端口映射到主機的6379端口
redis-server --appendonly yes : 在容器執行redis-server啟動命令,並打開redis持久化配置

相關配置

Spring Boot提供的資料訪問框架Spring Data Redis基於Jedis。可以通過引入spring-boot-starter-redis來配置依賴關係。

加入pom的依賴

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<!-- 1.5的版本預設連接池是jedis,2.0以上預設連接池是lettuce, 這邊採用jedis,所以排除lettuce -->
<exclusions>
<exclusion>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</exclusion>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- jedis客戶端 -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<!-- spring2.X集成redis所需common-pool2,使用jedis必須依賴它 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>

參數配置

在src/main/resources/application.properties中配置Redis服務端訊息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# REDIS (RedisProperties)
# Redis資料庫索引(預設為0)
spring.redis.database=0
# Redis伺服器地址
spring.redis.host=localhost
# Redis伺服器連接端口
spring.redis.port=6379
# Redis伺服器連接密碼(預設為空)
spring.redis.password=
# 連接池最大連接數(使用負值表示沒有限制)
spring.redis.pool.max-active=8
# 連接池最大阻塞等待時間(使用負值表示沒有限制)
spring.redis.pool.max-wait=-1
# 連接池中的最大空閒連接
spring.redis.pool.max-idle=8
# 連接池中的最小空閒連接
spring.redis.pool.min-idle=0
# 連接超時時間(毫秒)
spring.redis.timeout=1000

建立 Customer

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
package com.jj.learning.springboot.chapter23.domain;

import java.io.Serializable;

public class Customer implements Serializable {

    /**
     * serialVersionUID
     */
    private static final long serialVersionUID = 1L;

    private String name;

    private Integer age;

    public Customer(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

}

建立 RedisObjectSerializer (實現對象的序列化接口)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
package com.jj.learning.springboot.chapter23;

import org.springframework.core.convert.converter.Converter;
import org.springframework.core.serializer.support.DeserializingConverter;
import org.springframework.core.serializer.support.SerializingConverter;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;

public class RedisObjectSerializer implements RedisSerializer<Object> {

    private Converter<Object, byte[]> serializer = new SerializingConverter();
    private Converter<byte[], Object> deserializer = new DeserializingConverter();

    static final byte[] EMPTY_ARRAY = new byte[0];

    public Object deserialize(byte[] bytes) {
      if (isEmpty(bytes)) {
        return null;
      }

      try {
        return deserializer.convert(bytes);
      } catch (Exception ex) {
        throw new SerializationException("Cannot deserialize", ex);
      }
    }

    public byte[] serialize(Object object) {
      if (object == null) {
        return EMPTY_ARRAY;
      }

      try {
        return serializer.convert(object);
      } catch (Exception ex) {
        return EMPTY_ARRAY;
      }
    }

    private boolean isEmpty(byte[] data) {
      return (data == null || data.length == 0);
    }
  }

建立 RedisConfig (配置針對Customer的RedisTemplate實例)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
package com.jj.learning.springboot.chapter23;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import com.jj.learning.springboot.chapter23.domain.Customer;

@Configuration
public class RedisConfig {

    @Bean
    JedisConnectionFactory jedisConnectionFactory() {
        return new JedisConnectionFactory();
    }

    @Bean
    public RedisTemplate<String, Customer> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Customer> template = new RedisTemplate<String, Customer>();
        template.setConnectionFactory(jedisConnectionFactory());
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new RedisObjectSerializer());
        return template;
    }


}

測試

撰寫測試

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
package com.jj.learning.springboot.chapter23;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;

import com.jj.learning.springboot.chapter23.domain.Customer;

@RunWith(SpringRunner.class)
@SpringBootTest
public class Chapter23ApplicationTests {

    @Autowired
    private RedisTemplate<String, Customer> redisTemplate;

    @Test
    public void test() throws Exception {

        // 新增/保存Customer
        Customer customer = new Customer("J.J.Huang", 18);
        redisTemplate.opsForValue().set(customer.getName(), customer);
        customer = new Customer("K.K.Huang", 28);
        redisTemplate.opsForValue().set(customer.getName(), customer);
        customer = new Customer("L.L.Huang", 38);
        redisTemplate.opsForValue().set(customer.getName(), customer);

        // 取得並比對年齡
        Assert.assertEquals(18, redisTemplate.opsForValue().get("J.J.Huang").getAge().longValue());
        Assert.assertEquals(28, redisTemplate.opsForValue().get("K.K.Huang").getAge().longValue());
        Assert.assertEquals(38, redisTemplate.opsForValue().get("L.L.Huang").getAge().longValue());

    }

}

測試結果

我們可以透過Redis-cli指令去查詢看這個是否有寫入

註:以上參考了
SpringBoot2.0+整合redis,使用 RedisTemplate操作redis
oKongSpringBoot | 第十一章:Redis的集成和简单使用文章。
程序猿DD-翟永超Spring Boot中使用Redis数据库 文章。