spring data redis repostory

转载自 https://blog.csdn.net/wlwlwlwl015/article/details/52863821

前言

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.datagroupId><artifactId>spring-data-redisartifactId><version>1.7.4.RELEASEversion>
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):


<dependency><groupId>redis.clientsgroupId><artifactId>jedisartifactId><version>2.8.0version>
dependency>

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

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


<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" /><bean id="jedisConnectionFactory"class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"p:host-name="192.168.111.11" p:port="6379" /><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 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 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 stringSerializer = new StringRedisSerializer();/*** Constructs a new RedisTemplate 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(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中加入如下配置:


<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"p:connection-factory-ref="jedisConnectionFactory"><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 users = new ArrayList();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 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 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。


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部