前言

Spring Data Redis是Spring Data大家族的一部分,提供了基于spring应用的简易配置与redis服务访问,它为存储与交互提供了低级(low-level)和高级的(high-level)封装与抽象,使得用户不必再关注底层,正如其官网给出的定义:

Spring Data Redis, part of the larger Spring Data family, provides easy configuration and access to Redis from Spring applications. It offers both low-level and high-level abstractions for interacting with the store, freeing the user from infrastructural concerns.

本篇blog主要记录一下Spring Data Redis在基于spring的web项目中的应用与配置,版本为当前最新的GA(1.7.4),同时也重点记录了该版本的新特性之一:Redis Repositories。

快速入门

按照官方的Quick Start我们先快速进行一个简单的入门,首先第一步是引入spring-data-redis的maven依赖,当前最新的GA版本是1.7.4:

<dependency><groupId>org.springframework.data</groupId><artifactId>spring-data-redis</artifactId><version>1.7.4.RELEASE</version>
</dependency>

同时需要注意官方文档给出了Requirements(必备环境):

如上图,Spring Data Redis 1.x需要JDK 6.0及以上版本,Spring需要4.2.8.RELEASE及以上版本,同时Redis也要保证在2.6.x或更高的版本。Spring Data Redis还依赖了commons-logging,commons-pool2以及jedis,所以接下来还需要引入jedis的依赖,此处我选择的版本是2.8.0(当前最新版为2.9.0 Jul, 2016):

<!-- jedis -->
<dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>2.8.0</version>
</dependency>

依赖添加完毕后就可以开始配置编码了,依照官方的Quick Start,我们接下来应该做的是配置一个RedisTemplate:

如上图,我们这里稍做修改,添加我们自己的host-name、port、password等(如果有的话),还有别忘了在spring配置文件中添加schema(xmlns:p):

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"><!-- 注解扫描 --><context:component-scan base-package="com.wl.controller" /><!-- jedisConnectionFactory --><bean id="jedisConnectionFactory"class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"p:host-name="192.168.111.11" p:port="6379" /><!-- redisTemplate --><bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"p:connection-factory-ref="jedisConnectionFactory" /></beans>

如上所示,定义好了redisTemplate之后就可以在程序中注入测试了,看一个简单的Test Case:

package com.wl.test;import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath*:applicationContext.xml" })
@WebAppConfiguration
public class SpringRedisTest {@Autowiredprivate RedisTemplate<String, String> template;@Testpublic void testFirst() {// set username wlwlwlwl015template.opsForValue().set("username", "wlwlwlwl015");// get usernameSystem.out.println(template.opsForValue().get("username"));}}

如上所示,16行通过@Autowired注入了RedisTemplate,22行和24行则是调用了redis最简单的两个字符串操作命令set key valueget key,运行junit test case可以成功看到键值的存取:

通过RedisTemplate存取完全没有问题,那么再看一下redis控制台下是否已成功添加了这对key-value:

如上图,仿佛有些不对劲,在key-value前面均加了一串字符串,这是由于RedisSerializer默认使用的是JdkSerializationRedisSerializer,这个具体后面再说,本小节仅仅是Quick Start,那么至此Quick Start就算成功完成了,接下来具体记录一下Spring Data Redis的常用API与项目的集成封装。

常用API与Serializer(序列化)

接下来看一下Spring Data Redis中的常用API与对象操作,毕竟这些才是我们在实际项目中会频繁用到的,依旧参考官方文档,可以看到一个Operational views的表格:

如上图,Spring Redis Data针对jedis客户端的api进行了重新归类与封装,将同一类型的操作封装为Operation接口,如上面的Key Type OperationsKey Bound Operations,其中Key Type Operations顾名思义也就是根据键类型给所有操作进行分类,类别如下:

  • ValueOperations:简单K-V操作
  • SetOperations:set类型数据操作
  • ZSetOperations:zset类型数据操作
  • HashOperations:map类型的数据操作
  • ListOperations:list类型的数据操作

正如在Quick Start中用到的template.opsForValue()也就是第一个ValueOperations了,而后面的Key Bound Operations则提供了对key的”bound”(绑定)便捷化操作的API,可以通过bound封装指定的key,然后进行一系列的操作而无须“显式”的再次指定Key,举个简单例子:

@Test
public void testBound(){BoundValueOperations<String, String> boundValueOps = template.boundValueOps("username");System.out.println(boundValueOps.get());boundValueOps.set("wlwlwlwl is good!");System.out.println(boundValueOps.get());
}

很好理解,接下来介绍重点内容——序列化/反序列化(RedisSerializer),Spring Data Redis提供了多种可选择策略。官方文档的5.7小节针对Serializers只有一小段概述,下面是我截取的一小段重点内容:

Multiple implementations are available out of the box, two of which have been already mentioned before in this documentation: the StringRedisSerializer and the JdkSerializationRedisSerializer. However one can use OxmSerializer for Object/XML mapping through Spring 3 OXM support or either JacksonJsonRedisSerializer, Jackson2JsonRedisSerializer or GenericJackson2JsonRedisSerializer for storing data in JSON format.

如上所示,提供了多种开箱即用的实现,官方文档中已经被提过两种,分别是:

  • StringRedisSerializer
  • JdkSerializationRedisSerializer

第二种在上面也提过了,它是RedisTemplate提供的默认序列化方式,在源码中可以看到:

private RedisSerializer<?> defaultSerializer;private RedisSerializer keySerializer = null;
private RedisSerializer valueSerializer = null;
private RedisSerializer hashKeySerializer = null;
private RedisSerializer hashValueSerializer = null;private RedisSerializer<String> stringSerializer = new StringRedisSerializer();/*** Constructs a new <code>RedisTemplate</code> instance.*/
public RedisTemplate() {}public void afterPropertiesSet() {super.afterPropertiesSet();boolean defaultUsed = false;if (defaultSerializer == null) {defaultSerializer = new JdkSerializationRedisSerializer(classLoader != null ? classLoader : this.getClass().getClassLoader());}if (enableDefaultSerializer) {if (keySerializer == null) {keySerializer = defaultSerializer;defaultUsed = true;}if (valueSerializer == null) {valueSerializer = defaultSerializer;defaultUsed = true;}if (hashKeySerializer == null) {hashKeySerializer = defaultSerializer;defaultUsed = true;}if (hashValueSerializer == null) {hashValueSerializer = defaultSerializer;defaultUsed = true;}}if (enableDefaultSerializer && defaultUsed) {Assert.notNull(defaultSerializer, "default serializer null and not all serializers initialized");}if (scriptExecutor == null) {this.scriptExecutor = new DefaultScriptExecutor<K>(this);}initialized = true;
}

如上所示,23行指定默认defaultSerializer为JdkSerializationRedisSerializer,之所以上面通过RedisTemplate设置的key-value在redis控制台看加了一串字符串,是因为JdkSerializationRedisSerializer对key和value都进行了序列化,变成了字节序列(byte[]),然后再调用jedis进行存储的,而StringRedisSerializer是根据指定的charset对数据的字节序列编码成string,更适用于字符串场景,相当于new String(bytes, charset)string.getBytes(charset)的直接封装,也更加轻量与高效,所以此处将默认的JdkSerializationRedisSerializer替换成StringRedisSerializer就可以正常存取键值了,在我们的RedisTemplate中加入如下配置:

<!-- redisTemplate -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"p:connection-factory-ref="jedisConnectionFactory"><!-- 序列化方式 建议key/hashKey采用StringRedisSerializer。 --><property name="keySerializer"><bean
            class="org.springframework.data.redis.serializer.StringRedisSerializer" /></property><property name="hashKeySerializer"><bean
            class="org.springframework.data.redis.serializer.StringRedisSerializer" /></property><property name="valueSerializer"><bean
            class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" /></property><property name="hashValueSerializer"><bean
            class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" /></property>
</bean>

再回头看一下官方文档中关于Serializer的那一小段介绍,还提到了OxmSerializer和JacksonJsonRedisSerializer这两种策略,顾名思义,前者提供了将javabean与xml之间的转换能力(xml格式存储),而后者提供了javabean与json之间的转换能力(json格式存储,且依赖jackson-json工具包),由于实际项目中最常用的还是针对序列化对象的存取,所以接下来就记录一下对象操作,但并考虑使用以上两种,因为无论是json还是xml,他们本身仍然是String,并且以上两种策略封装和编程都较为复杂,性能也存在一些问题,在当前版本中我们有更好的选择,Spring Data Redis在最新版1.7.x中为我们提供了Redis Repositories,可以无缝的转换并存储domain objects,使用的数据类型为哈希(hash),下面重点看一下Redis Repositories的应用。

Redis Repositories

在Spring Data Redis1.7的新特性中,除了支持Redis集群外,我们还可以看到另一条重要的新特性——Spring Data Repository abstractions :

首先看一下官方文档中对Redis Repositories的简介:

如上所示,正如官方文档的介绍,Redis Repositories允许通过redis的hash类型无缝的存储以及转换领域对象,应用了自定义的映射策略并且利用了二级索引。接下来具体看一下用法,还需要注意一下如果要使用Redis Repositories,那么redis服务器的版本不能低于2.8:

Redis Repositories requires at least Redis Server version 2.8.0.

接下来看一下如何使用。

基础用法(Usage)

根据官方文档,首先第一步是在我们的实体bean上添加注解@RedisHash,并且在标识属性(或主键)上添加@Id注解,这两个注解负责创建用于存储对象hash的key,例如:

package com.wl.bean;import java.io.Serializable;import org.springframework.data.annotation.Id;
import org.springframework.data.redis.core.RedisHash;@RedisHash("users")
public class User implements Serializable{private static final long serialVersionUID = 1L;@Idprivate String username;private String password;private String nickname;private String email;private String filePath;public User() {}}

第二步需要创建一个repository接口来存取数据,根据官方的Example改写后如下:

package com.wl.dao;import org.springframework.data.repository.CrudRepository;public interface BaseRepository<T> extends CrudRepository<T, String> {}

用过spring data的话应该对这个接口比较熟悉了,CrudRepository为我们提供了一组基础的CRUD方法,有了这个基础接口之后,我们下面需要做的就通过Spring配置将bean和这个接口关联起来,正如官方文档的原话:

As our repository extends CrudRepository it provides basic CRUD and finder operations. The thing we need in between to glue things together is the according Spring configuration.

以User为例,我们再创建一个UserRepository接口:

package com.wl.dao;import com.wl.bean.User;public interface UserRepository extends BaseRepository<User>{}

下面看一下这个配置类:

package com.wl.dao;import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;
import org.springframework.stereotype.Component;import com.wl.bean.User;@Component("userDao")
@EnableRedisRepositories
public class UserDao {}

如上所示,关键点就是@EnableRedisRepositories,该注解表示启用Repositories,接下来我们就可以将UserRepository注入到我们的业务组件中使用了,下面是一个简单的测试方法:

package com.wl.test;import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;import com.wl.bean.User;
import com.wl.dao.UserRepository;@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath*:applicationContext.xml" })
@WebAppConfiguration
public class SpringRedisTest {@Autowired private UserRepository repo;@Testpublic void testRepositorySave(){//User u = new User("wangliang", "123", "raito", "raito@w.com");//repo.save(u);List<User> users = new ArrayList<User>();users.add(new User("shanshan", "123", "杉杉", "shanshan@qq.com"));users.add(new User("xiaoming", "123", "小明", "xm@qq.com"));users.add(new User("xiaohong", "123", "小红", "xh@qq.com"));repo.save(users);}@Testpublic void testRepositoryGet(){//User u = repo.findOne("wangliang");//System.out.println(u);Iterator<User> iterator = repo.findAll().iterator();while(iterator.hasNext()){System.out.println(iterator.next());}}}

如上所示,主要测试了List的存取,首先运行第一个存List的测试方法:

可以看到测试通过,接下来在redis控制台看一下数据:

如上图,可以看到所有hash的键格式均是@RedisHash("users")的参数值和@Id注解的属性名拼接而成的(keyspace:id),所以再次强调@Id务必要标记主键或者是数据库中的唯一标识符。save正常,再来看一下常用的findAll,运行第二个测试方法:

如上所示,测试通过,并且List中的数据可以成功返回并输出,Redis Repository的其它api就不再一一演示,可以发现用起来确实很爽,很强大,关于基础的使用方法(Usage)就暂且介绍到这里。

对象哈希映射(Object to Hash Mapping)

回顾上一小节,Redis Repository支持通过hash类型持久化对象,将对象的每个属性都映射的很好:

如上图,_class属性还映射了全类名,那么Redis Repository是如何正确映射对象的全部属性呢?根据官方文档的说明,实际上是通过一个RedisConverter(转换器)来实现的,这个转换器的默认实现就是org.springframework.core.convert.converter.Converter,在上图的映射列表中,所有的映射属性都属于Simple Type,官方文档中给出了一张默认的映射规则表:

如上图,分为5种类型,分别是:

  1. 简单类型(Simple Type)
  2. 符合类型(Complex Type)
  3. 简单列表类型(List of Simple Type)
  4. 简单K-V映射类型(Map of Simple Type)
  5. 符合列表类型(List of Complex Type)
  6. 符合K-V映射类型(Map of Complex Type)

每种映射类型都提供了对应的例子,当然这都是官方默认提供的,我们还可以通过程序自定义,由于我目前的项目只涉及简单类型,所以关于自定义映射就不做过多说明,有需求的朋友可以参考官方文档。

Keyspaces

keyspace用于创建hash键的前缀,默认的前缀是getClass().getName()即全类名,这里的默认意思就是说当我们的@RedisHash注解没有指定参数时,默认会用全类名做为前缀:

如上图,这个hash键的前缀就是默认生成的,除了通过修改@RedisHash注解,还可以使用编程的形式来指定前缀,此时就需要创建一个自定义的KeyspaceConfiguration:

package com.wl.util;import java.util.Collections;import org.springframework.data.redis.core.convert.KeyspaceConfiguration;import com.wl.bean.User;public class MyKeyspaceConfiguration extends KeyspaceConfiguration {@Overrideprotected Iterable<KeyspaceSettings> initialConfiguration() {return Collections.singleton(new KeyspaceSettings(User.class, "userme"));}}

如上所示,很好理解,这段代码的作用就是将keyspace指定为字符串“userme”,定义好KeyspaceConfiguration之后在@EnableRedisRepositories注解中声明引用即可:

package com.wl.dao;import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;
import org.springframework.stereotype.Component;import com.wl.bean.User;
import com.wl.util.MyKeyspaceConfiguration;@Component("userDao")
@EnableRedisRepositories(keyspaceConfiguration = MyKeyspaceConfiguration.class)
public class UserDao {@Autowired private UserRepository repo;}   

再次运行junit测试插入1条数据,可以看到此时的key前缀已经改变:

Redis Repository还有更多高级内容,如二级索引(Secondary Indexes)、对象过期时间(Time To Live)、查询(Queries and Query Methods)等等,感兴趣的朋友可以参考Spring Data Redis官方文档:http://docs.spring.io/spring-data/redis/docs/1.7.4.RELEASE/reference/html/

总结

简单介绍一下Spring Data Redis的基础用法以及1.7新特性——Redis Repositories,希望对遇到同样问题的朋友有所帮助,The End。

Spring Data Redis 实践相关推荐

  1. Spring Data Redis 正确使用姿势

    课程简介 本课程主要讲解常规 Redis 的写法,Redis 和 Spring 的结合使用,即 Spring Data Redis,以及 Redis 在工作中的正确使用姿势,Redis 和 Sprin ...

  2. Spring data redis 异常

    2019独角兽企业重金招聘Python工程师标准>>> spring 集成 spring-data-redis 版本: spring低版本 + spring-data-redis 高 ...

  3. 使用Spring Data Redis操作Redis(集群版)

    说明:请注意Spring Data Redis的版本以及Spring的版本!最新版本的Spring Data Redis已经去除Jedis的依赖包,需要自行引入,这个是个坑点.并且会与一些低版本的Sp ...

  4. Redis - Spring Data Redis 操作 Jedis 、Lettuce 、 Redisson

    文章目录 官网 Jedis VS Lettuce Jedis Code POM依赖 配置文件 配置类 单元测试 Lettuce Code Redisson Code POM依赖 配置文件 配置类 单元 ...

  5. Spring Boot使用Spring Data Redis操作Redis(单机/集群)

    说明:Spring Boot简化了Spring Data Redis的引入,只要引入spring-boot-starter-data-redis之后会自动下载相应的Spring Data Redis和 ...

  6. Java Spring Data Redis实战与配置参数详解 application.properties...

    Redis作为开源分布式高并发缓存,使用范围非常广泛,主流互联网公司几乎都在使用. Java Spring Boot 2.0实战开发Redis缓存可以参考下面的步骤,Redis安装可以直接使用Linu ...

  7. Spring Data Redis与Jedis的选择(转)

    说明:内容可能有点旧,需要在业务上做权衡. Redis的客户端有两种实现方式,一是可以直接调用Jedis来实现,二是可以使用Spring Data Redis,通过Spring的封装来调用.应该使用哪 ...

  8. Spring Data Redis—Pub/Sub(附Web项目源码)

    一.发布和订阅机制 当一个客户端通过 PUBLISH 命令向订阅者发送信息的时候,我们称这个客户端为发布者(publisher). 而当一个客户端使用 SUBSCRIBE 或者 PSUBSCRIBE ...

  9. 一文搞定 Spring Data Redis 详解及实战

    转载自  一文搞定 Spring Data Redis 详解及实战 SDR - Spring Data Redis的简称. Spring Data Redis提供了从Spring应用程序轻松配置和访问 ...

最新文章

  1. 浙大这个班诞生128家创业公司,总市值高达千亿!
  2. elasticsearch建立索引操作的API
  3. VTK:图像索贝尔Sobel用法实战
  4. linux中循环删除脚本,shell脚本:遍历删除
  5. 分布式光伏补贴_2018年国家光伏并网补贴标准、政策
  6. vue-cli(vue脚手架)搭建
  7. x-pack 功能介绍及配置传输层安全性(TLS / SSL)
  8. goharbor harbor-helm 搭建 记录
  9. 2021年啤酒酿造行业发展研究报告
  10. 2021肿瘤早筛行业研究报告
  11. 游戏加加导致cpu降频
  12. 10 款新鲜出炉的jQuery UI插件
  13. SpringBoot初学笔记(SpringBoot实战之数据库相关操作)
  14. vmvare打开虚拟机时报错:vmx文件已损坏
  15. 天池大赛:街景字符编码识别——Part2:数据读取与数据扩增
  16. python停止线程_python线程之八:线程停止的3种方式,5个实例
  17. 社交类App如何防黑产垃圾用户?
  18. 编写敏感词过滤程序 说明:在网络程序中,如聊天室、聊天软件等,经常需要对一些用户所提交的聊天内容中的敏感性词语进行过滤。 如“性”、“色情”、“爆炸”、“恐怖”、“枪”、“军火”等,这些都不可以在网
  19. redist 3 常用命令
  20. 什么是天使轮?什么是A轮融资?B轮融资?

热门文章

  1. 《所谓情商高,就是会说话》读书笔记
  2. Ratel不进行预测,一段时间后恢复正常
  3. STM32F103C8T6个人学习之路01-芯片介绍
  4. python爬虫实践之下载轻音乐
  5. 2021年茶艺师(中级)免费试题及茶艺师(中级)模拟试题
  6. 优化-规划问题(数学建模)
  7. 计算机体系结构实验三 指令调度和延迟分支
  8. 二、伊森商城 环境 虚拟机配置 p3
  9. 看设计师大牛如何将用户体验与建站融会贯通
  10. TI男选隐形眼镜之机器学习