springboot中使用redis详解

一、redis简介

redis是一款高性能key-value(键值对)内存型数据库,是非关系型数据库的一种,它采用单线程的架构方式,避免了多线程存在的锁处理造成的资源耗费,读取速度非常快,非常适合变化不是太大但数据量很大的数据的存储和读取。
redis中的数据类型:String、list、hash、zset、set五种。

二、使用场景

项目中涉及到数据查询的操作,先从redis中查询,若redis中不存在则从数据库中查询,再更新到redis中,以后再次执行相同的查询则直接从redis中查询,提高了效率。

三、springboot中使用redis
  1. pom.xml中配置依赖

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-data-redisartifactId>
        dependency>

2、application.properties中配置redis相关的参数

##配置redis
spring.redis.database=0
spring.redis.host=119.3.250.240
spring.redis.password=888888
spring.redis.port=6379

3、使用redis
redis中有两个模板类:RedisTemplate和StringRedisTemplate。通过模板类可以对redis数据库进行增删改查的操作,redis数据库中存放数据是要对key、value进行序列化的,RedisTemplate模板类默认采用JdkSerializationRedisSerializer序列化类对key和value进行序列化;而StringRedisTemplate默认采用StringRedisSerializer序列化类对key和value进行序列化。
上面说了这么多理论有啥用?对项目有什么影响?如何在项目中使用呢?别急,咱们下面就结合代码进行说明。

1)如果采用StringRedisTemplate模板,首先看它的下源码:

/**
从源码中可以看到,StringRedisTemplate模板类默认采用StringRedisSerializer序列化类对
key和value进行序列化,通过该模板类传参时,key和value要求是String类型。
*/
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);
    }
}

下面用StringRedisTemplate做个小测试:

@SpringBootTest
class DemoApplicationTests {
	//使用StringRedisTemplate模板
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Test
   public void junitTest() {
   		//往redis中存入key、value键值对
        stringRedisTemplate.opsForValue().set("webAddress","www.54gwz.cn");
		//从redis中取出key对应的value值
        System.out.println("---webAddress-->"+stringRedisTemplate.opsForValue().get("webAddress"));
    }
}

//单元测试日志截取如下:
2020-06-17 11:21:39.891  INFO 77817 --- [           main] io.lettuce.core.EpollProvider            : Starting without optional epoll library
2020-06-17 11:21:39.894  INFO 77817 --- [           main] io.lettuce.core.KqueueProvider           : Starting without optional kqueue library
----------------webAddress----------->www.54gwz.cn

redis客户端查询结果如下:

119.3.250.240:6379> keys *
1) "webAddress"
119.3.250.240:6379> get webAddress
"www.54gwz.cn"

2)如果采用RedisTemplate模板,首先看下它的源码(部分截取):

通过源码分析得到key、value、hashKey、hashValue均默认采用JdkSerializationRedisSerializer方式进行了序列化。

public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperations<K, V>, BeanClassLoaderAware {
    private boolean initialized = false;
    private boolean enableDefaultSerializer = true;
    @Nullable
    private RedisSerializer<?> defaultSerializer;
    @Nullable
    private RedisSerializer keySerializer = null;
    @Nullable
    private RedisSerializer valueSerializer = null;
    @Nullable
    private RedisSerializer hashKeySerializer = null;
    @Nullable
    private RedisSerializer hashValueSerializer = null;
    private RedisSerializer<String> stringSerializer = RedisSerializer.string();

    public RedisTemplate() {
    }

    public void afterPropertiesSet() {
        super.afterPropertiesSet();
        boolean defaultUsed = false;
		//defaultSerializer默认序列化类为JdkSerializationRedisSerializer
        if (this.defaultSerializer == null) {
            this.defaultSerializer = new JdkSerializationRedisSerializer(this.classLoader != null ? this.classLoader : this.getClass().getClassLoader());
        }
		/**key、value、hashKey、hashValue均默认采用JdkSerializationRedisSerializer
		的方式进行了序列化
		*/
        if (this.enableDefaultSerializer) {
            if (this.keySerializer == null) {
                this.keySerializer = this.defaultSerializer;
                defaultUsed = true;
            }

            if (this.valueSerializer == null) {
                this.valueSerializer = this.defaultSerializer;
                defaultUsed = true;
            }

            if (this.hashKeySerializer == null) {
                this.hashKeySerializer = this.defaultSerializer;
                defaultUsed = true;
            }

            if (this.hashValueSerializer == null) {
                this.hashValueSerializer = this.defaultSerializer;
                defaultUsed = true;
            }
        }

        if (this.enableDefaultSerializer && defaultUsed) {
            Assert.notNull(this.defaultSerializer, "default serializer null and not all serializers initialized");
        }

        if (this.scriptExecutor == null) {
            this.scriptExecutor = new DefaultScriptExecutor(this);
        }

        this.initialized = true;
    }

下面我们用这种默认的JdkSerializationRedisSerializer序列化的方式进行一个小测验:

@SpringBootTest
class DemoApplicationTests {

    @Autowired
    private RedisTemplate redisTemplate;

    @Test
   public void junitTest() {
        redisTemplate.opsForValue().set("username","wangxinli");
        System.out.println("---username-->"+redisTemplate.opsForValue().get("username"));
    }
}
执行单元测试打印日志结果:(结果正确!)
2020-06-17 17:57:40.440  INFO 1373 --- [main] io.lettuce.core.EpollProvider: Starting without optional epoll library
----------------username----------->wangxinli

此时在redis客户端进行查询:发现username前面会有一连串特殊字符,原因在于key值进行了JdkSerializationRedisSerializer序列化,如果想去掉key值的特殊字符,需要对key值指定序列化方式。

119.3.250.240:6379> keys *
1) "\xac\xed\x00\x05t\x00\busername"
2) "webAddress"

自定义序列化方式:

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
		//指定key、hashKey的序列化方式为StringRedisSerializer
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
		//指定value、hashValue的序列化方式为JdkSerializationRedisSerializer
        redisTemplate.setHashValueSerializer(new JdkSerializationRedisSerializer());
        redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
		//redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer(Object.class));
        redisTemplate.setConnectionFactory(redisConnectionFactory);
		redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}

再次执行看下效果:

@SpringBootTest
class DemoApplicationTests {
	/**此处自动装配的RedisTemplate对象的序列化方式就是上面自定义的,即(key和hashKey
	采用StringRedisSerializer,value和hashValue采用的			 
	JdkSerializationRedisSerializer)
	*/
    @Autowired
    private RedisTemplate redisTemplate;

    @Test
   public void junitTest() {
        redisTemplate.opsForValue().set("usernameSerialize","wangxinliSerialize");
        System.out.println("---usernameSerialize-->"+redisTemplate.opsForValue().get("usernameSerialize"));
    }
}

执行单元测试,看下打印的日志效果:(没有问题)

2020-06-17 18:27:24.330  INFO 1738 --- [main] io.lettuce.core.EpollProvider
2020-06-17 18:27:24.331  INFO 1738 --- [main].....省略
---usernameSerialize-->wangxinliSerialize

再看下redis客户端:发现usernameSerialize前面的特殊字符消失了,我们的更改序列化方式
生效啦,我们成功啦!!!!

119.3.250.240:6379> keys *
1) "usernameSerialize"
2) "\xac\xed\x00\x05t\x00\busername"
119.3.250.240:6379> get usernameSerialize
"\xac\xed\x00\x05t\x00\x12wangxinliSerialize"

但别高兴的太早,有没有发现一个新的问题呢,usernameSerialize对应的value值也变成有特殊字符啦!!!!别担心,这是正常现象,因为value值也是采用的JdkSerializationRedisSerializer进行序列化的鸭!我们也可以采用上述指定序列化的方式进行更改。

注意一点:若采用JdkSerializationRedisSerializer序列化value、hashValue,则需要model中的类实现Serializable接口,此外还有Jackson2JsonRedisSerializer序列化方式,使用它不需要model实现Serializable接口。

你可能感兴趣的:(redis,springboot,redis)