从零学SpringBoot整合Redis

1. Redis的安装

为了方便学习,使用 Windows 系统对 Redis 进行讲解。由于 Redis 官方没有提供 Windows 版的安装包,但可以从GitHub 中来下载 Windows 版 Redis 安装包,下载:点击前往https://github.com/tporadowski/redis/releases】。

注意:Windows 安装包是某位“大神”根据 Redis 源码改造的,并非 Redis 官方提供。

进入 GitHub 的下载页面,Redis 支持 32 位和 64 位的 Window 系统,大家根据个人情况自行下载:
在这里插入图片描述

下载完成后,解压放入指定文件夹下(无需安装,解压即可),看到如下文件结构:
在这里插入图片描述

启动 redis-server 服务程序:
使用命令:> redis-server.exe redis.windows.conf
在这里插入图片描述

用 redis-cli 客户端连接:
完整命令:
redis-cli.exe -h 127.0.0.1 -a 'xxx' -p 6379

  • -h 表示redis服务器的 IP地址
  • -a 表示输入密码
  • -p 表示 redis服务器的端口

在这里插入图片描述

示例中设置了键值对 set myKey abc,并且读取也成功了。说明 Redis 安装成功。

2. SpringBoot整合Redis

SpringBoot 版本 2.1.8.RELEASE

2.1 添加依赖
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

<!--reids版本为1.4.1版本以上需要添加-->
<dependency>
  <groupId>org.apache.commons</groupId>
  <artifactId>commons-pool2</artifactId>
</dependency>

使用 lettuce 必须 导入 commons-pool2 包,否则在启动 SpringBoot项目时会报错。

2.2 单机版 application.yml 文件配置
server:
  port: 8080

spring:
  redis:
    database: 0
    port: 6379
    host: localhost
    password:
    lettuce:
      pool:
        # 连接池最大连接数(使用负值表示没有限制)
        max-active: 1024
        # 连接分配在池耗尽之前在抛出异常之前应阻止的最大时间量(连接池最大阻塞等待时间以毫秒为单位) 使用负值无限期地阻止
        max-wait: -1
        # 连接池中的最大空闲连接, 使用负值来表示无限数量的空闲连接
        max-idle: 200
        # 连接池中的最小空闲连接, 此设置只有在正值时才有效果
        min-idle: 5
    # 连接超时时间(毫秒)
    timeout: 30000

注:redis 数据源连接池的配置有所不同,jedis、lettuce。在 SpringBoot2 之后,默认就使用 lettuce了

不使用 jedis的原因?
jedis是比较优秀的框架,但有一些线程不安全的问题。在 lettuce 下得到了很好的解决,,lettuce 集成了 Netty IO 性能得到了保证及线程安全。

2.3 编写Redis核心配置类
// @Configuration注解 通常与@bean结合使用,当@bean注解到方法上,代表将该方法做为一个bean交给了spring容器管理
@Configuration
public class RedisConfig {
	// 表示创建 redisTemplate Bean
	@Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        
        /**
         *  redis默认使用 JDK序列化, 优点在反序列化时不需要声明class, 但序列化的数据是json的5倍大小, 这样就比较消耗redis的内存, 所以一般会重写 redis的序列化。
         *   
         *  spring提供的序列化器:
         *    Jackson2JsonRedisSerializer
         *    JdkSerializationRedisSerializer
         *    OxmSerializer
         *    StringRedisSerializer
         *    GenericToStringRedisSerializer
         *    GenericJackson2JsonRedisSerializer
         **/
        // 使用 Jackson2JsonRedisSerializer 序列化器, 将对象解析成可以序列化的对象
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
        // 使用Mapper对象进行转义
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        //开始序列化对象
        jackson2JsonRedisSerializer.setObjectMapper(om);

        // String 的序列化器
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // 设置 key 的序列化器为 StringRedisSerializer
        template.setKeySerializer(stringRedisSerializer);
        // 设置 hash key 的序列化器为 StringRedisSerializer
        template.setHashKeySerializer(stringRedisSerializer);
        
        // 设置 value 的序列化器为 Jackson2JsonRedisSerializer
        template.setValueSerializer(jackson2JsonRedisSerializer);
        // 设置 hash value 的序列化器为 Jackson2JsonRedisSerializer
        template.setHashKeySerializer(jackson2JsonRedisSerializer);
        
        template.afterPropertiesSet();
        return template;
    }
}

redis默认使用 JDK序列化,优点在反序列化时不需要声明class,但序列化后的数据是json的5倍大小,这样就比较消耗redis的内存,所以我们一般会重写 redis的序列化。

Spring提供常用的序列化器:

  • Jackson2JsonRedisSerializer
  • JdkSerializationRedisSerializer
  • StringRedisSerializer
  • GenericToStringRedisSerializer
  • GenericJackson2JsonRedisSerializer

关于序列化器也可以自定义实现,我们只需要实现 RedisSerializer<T> 接口即可。具体见下一次 自定义序列化器的实现。

2.4 编写 Redis工具类
@Component
public class RedisUtil {
	// 为了解决 静态属性变量的注入, 只能使用 ApplicationContext.getBean()的模式
	@SuppressWarnings("unchecked")
	private static RedisTemplate<String, Object> redisTemplate = AppContextHolder.getBean("redisTemplate", RedisTemplate.class);

	/**
     * 设置有效时间, 默认秒
     */
    public static boolean expire(final String key, final long timeout) {
        return expire(key, timeout, TimeUnit.SECONDS);
    }

    /**
     * 设置有效时间
     */
    public static boolean expire(final String key, final long timeout, final TimeUnit unit) {
        Boolean ret = redisTemplate.expire(key, timeout, unit);
        return ret != null && ret;
    }

    /**
     * 删除单个key
     */
    public static boolean del(final String key) {
        Boolean ret = redisTemplate.delete(key);
        return ret != null && ret;
    }

    /**
     * 删除多个key
     */
    public static long del(final Collection<String> keys) {
        Long ret = redisTemplate.delete(keys);
        return ret == null ? 0 : ret;
    }

    /**
     * 存入普通对象
     */
    public static void set(final String key, final Object value) {
        redisTemplate.opsForValue().set(key, value);
    }

    /**
     * 存入普通对象
     */
    public static void set(final String key, final Object value, final long timeout) {
        redisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS);
    }

    /**
     * 获取普通对象
     */
    public static Object get(final String key) {
        return redisTemplate.opsForValue().get(key);
    }
    
    /** -------------------Hash相关操作--------------------- */
    /**
     * 往Hash中存入数据
     */
    public static void hPut(final String key, final String filed, final Object value) {
        redisTemplate.opsForHash().put(key, filed, value);
    }

    /**
     * 往Hash中存入多个数据
     */
    public static void hPutAll(final String key, final Map<String, Object> filedMap) {
        redisTemplate.opsForHash().putAll(key, filedMap);
    }

    /**
     * 获取Hash中的数据
     */
    public static Object hGet(final String key, final String filed) {
        return redisTemplate.opsForHash().get(key, filed);
    }

    /**
     * 获取多个Hash中的数据
     */
    public static List<Object> hMultiGet(final String key, final Collection<Object> fileds) {
        return redisTemplate.opsForHash().multiGet(key, fileds);
    }

    /** -------------------Set相关操作--------------------- */
    /**
     * 往Set中存入数据
     */
    public static long sSet(final String key, final Object... values) {
        Long count = redisTemplate.opsForSet().add(key, values);        
        return count == null ? 0 : count;
    }

    /**
     * 删除Set中的数据
     */
    public static long sDel(final String key, final Object... values) {
        Long count = redisTemplate.opsForSet().remove(key, values);
        return count == null ? 0 : count;
    }
    
    /** -------------------List相关操作--------------------- */
    
    /**
     * 往List左侧中存入数据
     */
    public static long lPush(final String key, final Object value) {
        Long count = redisTemplate.opsForList().leftPush(key, value);
        return count == null ? 0 : count;
    }

    /**
     * 往List右侧中存入数据
     */
    public static long rPush(final String key, final Object value) {
        Long count = redisTemplate.opsForList().rightPush(key, value);
        return count == null ? 0 : count;
    }

    /**
     * 往List中左侧存入多个数据
     */
    public static long lPushAll(final String key, final Collection<Object> values) {
        Long count = redisTemplate.opsForList().leftPushAll(key, values);
        return count == null ? 0 : count;
    }

    /**
     * 往List中左侧存入多个数据
     */
    public static long lPushAll(final String key, final Object... values) {
        Long count = redisTemplate.opsForList().leftPushAll(key, values);
        return count == null ? 0 : count;
    }

    /**
     * 往List中右侧存入多个数据
     */
    public static long rPushAll(final String key, final Collection<Object> values) {
        Long count = redisTemplate.opsForList().rightPushAll(key, values);
        return count == null ? 0 : count;
    }

    /**
     * 往List中右侧存入多个数据
     */
    public static long rPushAll(final String key, final Object... values) {
        Long count = redisTemplate.opsForList().rightPushAll(key, values);
        return count == null ? 0 : count;
    }

    /**
     * 从List中获取begin到end之间的元素
     */
    public static List<Object> listGetRange(final String key, final int start, final int end) {
        return redisTemplate.opsForList().range(key, start, end);
    }

    /**
     * 从List左侧弹出数据
     */
    public static Object listGetL(final String key) {
        return redisTemplate.opsForList().leftPop(key);
    }

    /**
     * 从List右侧弹出数据
     */
    public static Object listGetR(final String key) {
        return redisTemplate.opsForList().rightPop(key);
    }
}
2.5 启动及测试
@RestController
@SpringBootApplication
public class SpringRedisApplication {

    // 存储 实体类
	@RequestMapping(value="/set", method=RequestMethod.GET)
	public String hello(){
		Account acc = new Account();
		acc.setId(3);
		acc.setUserId("admin");
		acc.setMoney(100);
		RedisUtil.set("admin", acc);
		return "ok";
	}
	
	@RequestMapping(value="/get", method=RequestMethod.GET)
	public String load(){
		Account acc = (Account)RedisUtil.get("admin");
		return acc.toString();
	}

    // 存储 字符串类型
	@RequestMapping(value="/setString", method=RequestMethod.GET)
	public String putString(@RequestParam(value="name") String name) {
		Integer c = 1;
		Object obj = RedisUtil.get("user:uid:" + name);
		if(obj != null) {
			c = 1 + (Integer)obj;		
		}
		RedisUtil.set("user:uid:" + name , c);		
		return "login number: " + c;
	}
	
	public static void main(String[] args) {
		SpringApplication.run(SpringRedisApplication.class, args);
	}
}

通过浏览器访问进行操作
在这里插入图片描述
在这里插入图片描述

总结

以上是使用 SpringBoot 的 RedisTemplate模板,实现了单机版的 Redis 操作。下一步计划讲解 Redis的 哨兵模式、集群模式 以及 pub/sub模式的使用。

想要源码可以私信

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值