SpringBoot整合redis

一、redis单机版

写在前面

  • 选中代码块,按control + alt + t:快捷tryCatch
  • 选中类名,按control + shift + t:快捷创建Junit Test

redis连接的准备工作

  • 如果是阿里云购买的服务器的话,需要开放redis的启动端口,默认端口为6379
  • 打开redis根目录下的redis.conf文件,将bind 127.0.0.1注释掉,即改为# bind 127.0.0.1,否则只能进行本地连接,从而报异常
  • 找到redis.conf文件中的protected-mode yes,将其改为protected-mode no,关闭保护模式,否则会报连接被终止的异常
  • 重启redis,重启的使用应携带conf文件进行重启,在redis的src文件下执行./redis-server ../redis.conf重启redis,直接重启配置文件并不会生效

redis相关配置

  • 依赖包引入
<!-- 引入redis依赖 -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

<!-- redis依赖commons-pool 这个依赖一定要添加 -->
<dependency>
	<groupId>org.apache.commons</groupId>
	<artifactId>commons-pool2</artifactId>
</dependency>
  • 配置springBoot的配置文件(application.properties或application.yml),此处配置的是application.properties
# redis相关配置
# redis数据库索引
spring.redis.database=0
# redis服务器地址
spring.redis.host=120.78.151.65
# redis服务器连接端口
spring.redis.port=6379
# redis服务器连接密码
spring.redis.password=
# 连接池最大连接数(负值表示没有限制)
spring.redis.lettuce.pool.max-active=8
# 连接池最大阻塞等待时间(负值表示无限制)
spring.redis.jedis.pool.max-wait=-1
# 连接池中的最大空闲连接
spring.redis.lettuce.pool.max-idle=8
# 连接池中的最小空闲连接
spring.redis.lettuce.pool.min-idle=0
# 连接超时时间(毫秒)
spring.redis.timeout=5000
  • 创建RedisConfig.java文件,配置自定义redisTemplate,解决因默认序列化JdkSerializationRedisSerializer导致的字符显示不正常的问题。
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
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.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
@AutoConfigureAfter(RedisAutoConfiguration.class)
public class RedisConfig {

    /**
     * 配置自定义redisTemplate
     * @return
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {

        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);

        //使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
        Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class);

        ObjectMapper mapper = new ObjectMapper();
        mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        serializer.setObjectMapper(mapper);

        template.setValueSerializer(serializer);
        //使用StringRedisSerializer来序列化和反序列化redis的key值
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(serializer);
        template.afterPropertiesSet();
        return template;
    }

}
  • 创建Junit测试实例进行Junit测试,Idea编译器中选中类名,control + shift + t快捷创建
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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 java.util.concurrent.TimeUnit;

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

    private Logger log = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    public void redisTemplate() {

        // redis存储的键名
        String key = "number";

        //如果不存在则设置值,存在的话则不设置
        redisTemplate.opsForValue().setIfAbsent(key, 1);

        //设置哈希值map值
        redisTemplate.opsForHash().put("map", "place", "北京");
        //获取到哈希值
        String place = (String) redisTemplate.opsForHash().get("map","place");
        log.info("[获取到的哈希值] - {}",place);

        //进行值的增加和减少(需要为Integer)
        redisTemplate.opsForValue().increment("number",-10);
        
        //log中的“{}”为占位符
        String value = (String) redisTemplate.opsForValue().get("school");
        log.info("[redis中 获取到的值] - [{}]",value);

        //设置有效时间为10秒的键值
        redisTemplate.opsForValue().set("flag","10",10, TimeUnit.SECONDS);
        String flag = (String) redisTemplate.opsForValue().get("flag");
        log.info("[获取到的有效时间为10秒的flag] - [{}]",flag);
    }
}

 

Redis整合遇到的坑

问题一:

  • SpringBoot整合Redis后连接Redsi出现超时问题

解决:

  • 网上的redis的相关配置中都是spring.redis.timeout=0,超时时间不能设置为0,可以设置为5000(根据实际情况设置)。

问题二:

  • 修改redis的conf文件后重启redis配置没有生效,一直报连接被主机中的软件中止。
org.springframework.data.redis.RedisSystemException: Redis exception; nested exception is io.lettuce.core.RedisException: java.io.IOException: 你的主机中的软件中止了一个已建立的连接。
...
Caused by: java.io.IOException: 你的主机中的软件中止了一个已建立的连接。
	at sun.nio.ch.SocketDispatcher.read0(Native Method)
	at sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:43)
	at sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:223)
	at sun.nio.ch.IOUtil.read(IOUtil.java:192)
	at sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:380)
	at io.netty.buffer.PooledUnsafeDirectByteBuf.setBytes(PooledUnsafeDirectByteBuf.java:288)
	at io.netty.buffer.AbstractByteBuf.writeBytes(AbstractByteBuf.java:1108)
	at io.netty.channel.socket.nio.NioSocketChannel.doReadBytes(NioSocketChannel.java:345)
	at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:131)
	at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:645)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:580)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:497)
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:459)
	at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:886)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.lang.Thread.run(Thread.java:748)

解决: