springboot-整合redis

本文详细介绍了SpringBoot中集成Redis的两种方式:手动配置Jedis和使用spring-boot-starter-data-redis。涵盖依赖添加、配置属性、组件创建、操作封装及测试步骤。同时对比了Jedis和Lettuce客户端,并提供了基于spring-data-redis的配置类示例。

springboot 集成redis有两种方式

  • 1、手动配置集成jedis
  • 2、使用spring-boot-starter-data-redis集成

手动配置集成jedis

1、添加依赖

jedis:连接redis
fastjson: 序列化工具,序列化为json格式

<dependency>
	    <groupId>redis.clients</groupId>
	    <artifactId>jedis</artifactId>
	</dependency>
	
	<dependency>
	    <groupId>com.alibaba</groupId>
	    <artifactId>fastjson</artifactId>
	    <version>1.2.38</version>
	</dependency>
	
2、配置属性
# redis
redis.host=localhost
redis.port=6379
redis.timeout=3
redis.password=
redis.poolMaxTotal=10
redis.poolMaxIdle=10
redis.poolMaxWait=3
3、配置redis组件
@Component
@ConfigurationProperties(prefix="redis")
public class RedisConfig {
    private String host;
    private int port;
    private int timeout;//秒
    private String password;
    private int poolMaxTotal;
    private int poolMaxIdle;
    private int poolMaxWait;//秒
    //setter and getter
}
4、创建redispool
@Service
public class RedisPoolFactory {

    @Autowired
    RedisConfig redisConfig;

    //redis无密码时,redisConfig.getPassword()改为null
    @Bean
    public JedisPool JedisPoolFactory() {
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxIdle(redisConfig.getPoolMaxIdle());
        poolConfig.setMaxTotal(redisConfig.getPoolMaxTotal());
        poolConfig.setMaxWaitMillis(redisConfig.getPoolMaxWait() * 1000);
        JedisPool jp = new JedisPool(poolConfig, redisConfig.getHost(), redisConfig.getPort(),
                redisConfig.getTimeout()*1000, redisConfig.getPassword(), 0);
        return jp;
    }
}

错误:ERR Client sent AUTH, but no password is set
客户端发送验证,但是redis服务器端没有设置密码
删除密码字段或设置redis服务器密码

5、RedisService封装对redis的操作

其中对象的存储使用fastjson序列化为json字符串

@Service
public class RedisService {

    @Autowired
    JedisPool jedisPool;
    /**
     * 获取当个对象
     * */
    public <T> T get(KeyPrefix prefix, String key,  Class<T> clazz) {
        Jedis jedis = null;
        try {
            jedis =  jedisPool.getResource();
            //生成真正的key
            //UserKey.getById,User.class 
            String realKey  = prefix.getPrefix() + key;
            String  str = jedis.get(realKey);
            T t =  stringToBean(str, clazz);
            return t;
        }finally {
            returnToPool(jedis);
        }
    }

    /**
     * 设置对象
     * */
    public <T> boolean set(KeyPrefix prefix, String key,  T value) {
        Jedis jedis = null;
        try {
            jedis =  jedisPool.getResource();
            String str = beanToString(value);
            if(str == null || str.length() <= 0) {
                return false;
            }
            //生成真正的key
            String realKey  = prefix.getPrefix() + key;
            int seconds =  prefix.expireSeconds();
            if(seconds <= 0) {
                jedis.set(realKey, str);
            }else {
                jedis.setex(realKey, seconds, str);
            }
            return true;
        }finally {
            returnToPool(jedis);
        }
    }

    /**
     * 判断key是否存在
     * */
    public <T> boolean exists(KeyPrefix prefix, String key) {
        Jedis jedis = null;
        try {
            jedis =  jedisPool.getResource();
            //生成真正的key
            String realKey  = prefix.getPrefix() + key;
            return  jedis.exists(realKey);
        }finally {
            returnToPool(jedis);
        }
    }

    /**
     * 增加值
     * */
    public <T> Long incr(KeyPrefix prefix, String key) {
        Jedis jedis = null;
        try {
            jedis =  jedisPool.getResource();
            //生成真正的key
            String realKey  = prefix.getPrefix() + key;
            return  jedis.incr(realKey);
        }finally {
            returnToPool(jedis);
        }
    }

    /**
     * 减少值
     * */
    public <T> Long decr(KeyPrefix prefix, String key) {
        Jedis jedis = null;
        try {
            jedis =  jedisPool.getResource();
            //生成真正的key
            String realKey  = prefix.getPrefix() + key;
            return  jedis.decr(realKey);
        }finally {
            returnToPool(jedis);
        }
    }

    private <T> String beanToString(T value) {
        if(value == null) {
            return null;
        }
        Class<?> clazz = value.getClass();
        if(clazz == int.class || clazz == Integer.class) {
            return ""+value;
        }else if(clazz == String.class) {
            return (String)value;
        }else if(clazz == long.class || clazz == Long.class) {
            return ""+value;
        }else {
            return JSON.toJSONString(value);
        }
    }

    @SuppressWarnings("unchecked")
    private <T> T stringToBean(String str, Class<T> clazz) {
        if(str == null || str.length() <= 0 || clazz == null) {
            return null;
        }
        if(clazz == int.class || clazz == Integer.class) {
            return (T)Integer.valueOf(str);
        }else if(clazz == String.class) {
            return (T)str;
        }else if(clazz == long.class || clazz == Long.class) {
            return  (T)Long.valueOf(str);
        }else {
            return JSON.toJavaObject(JSON.parseObject(str), clazz);
        }
    }

    private void returnToPool(Jedis jedis) {
        if(jedis != null) {
            jedis.close();
        }
    }

}
6、redis存储prefix设计

采用三层结构:
接口
抽象类

接口

public interface KeyPrefix {
    public int expireSeconds();//获取过期时间
    public String getPrefix();//获取封装后的key
}

抽象类

public abstract class BasePrefix implements KeyPrefix{

	
    private int expireSeconds;//过期时间单位秒
    private String prefix; //附加前缀

    public BasePrefix(String prefix) {//0代表永不过期
        this(0, prefix);
    }
    
    public BasePrefix( int expireSeconds, String prefix) {
        this.expireSeconds = expireSeconds;
        this.prefix = prefix;
    }
    public int expireSeconds() {
        return expireSeconds;
    }
    public String getPrefix() {
        String className = getClass().getSimpleName();
        return className+":" + prefix;
    }
}

实现类

public class UserKey extends BasePrefix{

	private UserKey(String prefix) {
		super(prefix);
	}

	public static UserKey getById = new UserKey("id");
	public static UserKey getByName = new UserKey("name");
}
7、测试
public class SampleController {
    @Autowired
    RedisService redisService;

     @RequestMapping("/redis/set")
    @ResponseBody
    public Result<Boolean> redisSet() {
        User user  = new User();
        user.setId(1);
        user.setName("1111");
        redisService.set(UserKey.getById, ""+1, user);//UserKey:id1
        return Result.success(true);
    }

    @RequestMapping("/redis/get")
    @ResponseBody
    public Result<User> redisGet() {
        User  user  = redisService.get(UserKey.getById, ""+1, User.class);
        return Result.success(user);
    }
}

获取的结果:
{“code”:0,“msg”:null,“data”:{“id”:1,“name”:“1111”}}

使用spring-boot-starter-data-redis

参考redis-10-spring-boot

  • jedis

jedis是redis的java客户端,通过它可以对redis进行操作。
与之功能相似的还包括:Lettuce等

  • spring-data-redis

spring-boot-data-redis 内部实现了对Lettuce和jedis两个客户端的封装,
默认使用的是Lettuce

1、添加依赖
 <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
  </dependency>
2、外部配置文件
  • application.yaml
    spring:
      redis:
        host: 127.0.0.1
        port: 6379
        password: null
        pool:
          max-idle: 300
          min-idle: 10
          max-active: 600
          max-wait: 1000
        timeout: 0
3、配置类
@Configuration
public class RedisConfig {

    @Autowired
    private RedisConnectionFactory redisConnectionFactory;

    /**
     * 实例化 RedisTemplate 对象
     * 
     */
    @Bean
    public RedisTemplate<String, Object> functionDomainRedisTemplate() {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        this.initRedisTemplate(redisTemplate, redisConnectionFactory);
        return redisTemplate;
    }

    /**
     * 序列化设置
     */
    private void initRedisTemplate(RedisTemplate<String, Object> redisTemplate, RedisConnectionFactory factory) {
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new JdkSerializationRedisSerializer());
        redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
        redisTemplate.setConnectionFactory(factory);
    }

    @Bean
    public HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForHash();
    }

    @Bean
    public ValueOperations<String, Object> valueOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForValue();
    }

    @Bean
    public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForList();
    }

    @Bean
    public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForSet();
    }

    @Bean
    public ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForZSet();
    }
}
spring-boot-starter-data-redis是Spring Boot提供的一个Starter,用于简化Spring Data Redis的配置和使用。Spring Data Redis是Spring提供的数据访问框架,提供了高级的Redis数据操作API,支持对Redis各种数据类型的操作以及事务、Pub/Sub消息等高级特性 [^1]。 ### 使用指南 在Spring Boot应用中使用spring-boot-starter-data-redis可以很方便地集成Redis。Spring Boot会自动在容器中生成一个RedisTemplate和一个StringRedisTemplate。RedisTemplate的泛型是<Object,Object>,且未设置数据存于Redis时key及value的序列化方式。这两个Bean使用@ConditionalOnMissingBean注解,若Spring容器中已有RedisTemplate对象,自动配置的RedisTemplate不会实例化,因此可自行编写配置类来配置RedisTemplate [^4]。 以下是一个简单的使用示例: ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; @Service public class RedisService { @Autowired private RedisTemplate<String, String> redisTemplate; public void setValue(String key, String value) { redisTemplate.opsForValue().set(key, value); } public String getValue(String key) { return redisTemplate.opsForValue().get(key); } } ``` ### 配置方法 首先,在`pom.xml`中添加依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> ``` 然后,在`application.properties`或`application.yml`中进行基本配置: ```properties spring.redis.host=localhost spring.redis.port=6379 spring.redis.password=yourpassword ``` 若要自定义RedisTemplate的序列化方式,可创建配置类: ```java 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.StringRedisSerializer; @Configuration public class RedisConfig { @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setConnectionFactory(redisConnectionFactory); template.setKeySerializer(new StringRedisSerializer()); template.setValueSerializer(new StringRedisSerializer()); return template; } } ``` ### 常见问题解决方案 - **序列化问题**:RedisTemplate默认未设置key和value的序列化方式,可能导致存储和读取数据时出现问题。可以通过自定义RedisTemplate的序列化方式来解决,如上述配置类中的示例 [^4]。 - **性能问题**:合理配置序列化与连接池参数,结合事务、管道等高级特性,可显著提升应用性能。对于大规模生产环境,建议进一步整合Redis集群与监控工具以实现高可用与稳定性 [^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值