使用Spring操作Redis的key-value数据
前言
最近工作一直忙的不可开交,小Alan已经很久没有和大家分享知识了,在深圳待了两年多,依然感觉自己还是个小菜鸟,工作中还是会遇到很多自己在短期内无法搞定的事情,每当这个时候总是会感觉到很沮丧,就会心态不好,最近也是,最后不得不把手上的事情转交给比较熟悉或者比较厉害的同事去搞定,或许这是每个开发都会经历的事情吧,小鸟要成长为老鸟,过程还是会比较艰难的。回归正题,今天跟大家一起聊聊Spring集成Redis吧,正好项目也把公司自己封装的一套jedis客户端操作换成了Spring Data Redis,自己过一遍也好在未来啃这个项目打下一些基础。
简单介绍
Redis是一种非关系型的数据库,采用key-value的形式存储数据,这跟我们平时使用的Java自带的哈希Map有很大的相似性,就好像是持久化版的哈希Map。要使用Spring来操作Redis数据库,我们需要用到Spring Data Redis,Spring Data的一个关键特性,面向模板的数据访问,能够在使用Redis的时候,给我们提供很大的帮助。Spring Data Redis包含了多个模板实现, 用来完成Redis数据库的数据存取功能。 为了创建Spring Data Redis的模板, 我们首先需要有一个Redis连接工厂。幸好,Spring Data Redis提供了四个连接工厂供我们选择。
具体实现
maven目前是非常火的项目管理技术,这里我们也使用maven来依赖我们需要的jar包,如果你不会maven,建议你把小Alan写的maven的相关知识过一遍,如图所示:
这里只给大家看图,不提供具体的pom结构代码,如果不会maven的,做为一名Java开发工程师,建议您把maven技术学会,只要随便跟着小Alan写的maven系列的知识过一遍也就对maven的整体使用有一个大概的了解了,并不是很难。
第一步:连接到Redis
Redis连接工厂会生成到Redis数据库服务器的连接。 Spring Data Redis为四种Redis客户端实现提供了连接工厂:
这里我们使用JedisConnectionFactory,如果是在平时的开发中,那就看哪种Redis客户端和连接工厂最适合自己的需求了,不过目前市面上用的最多的应该还是jedis客户端访问redis数据库。
将连接工厂配置为Spring中的bean,下图展示了通过注解的方式配置JedisConnectionFactory bean:
通过默认构造器创建的连接工厂会向localhost上的6379端口创建连接, 并且没有密码。 如果你的Redis服务器运行在其他的主机端口上,在创建连接工厂的时候,可以设置这些属性:
类似地, 如果你的Redis服务器配置为需要客户端认证的话, 那么可以通过调用setPassword()方法来设置密码:
但是这种方式在我们平时的开发中很少用到,在平时的开发中一般还是会采用spring配置文件的实现方式,代码如下:
1 # ######## spring redis begin 2 spring.redis.maxTotal=300 3 spring.redis.maxIdle=30 4 spring.redis.maxWaitMillis=4000 5 spring.redis.timeout=3000 6 spring.redis.hostName=127.0.0.1 7 spring.redis.port=6379 8 #spring.redis.password= 9 spring.redis.session.timeout=300 10 # ######## spring redis end
1 <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> 2 <property name="fileEncoding" value="UTF-8"></property> 3 <property name="locations"> 4 <list> 5 <value>classpath:config/*.properties</value> 6 </list> 7 </property> 8 </bean> 9 10 <!-- JEDIS连接池配置 --> 11 <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> 12 <!--新版是maxTotal,旧版是maxActive --> 13 <property name="maxTotal" value="${spring.redis.maxTotal}" /> 14 <property name="maxIdle" value="${spring.redis.maxIdle}" /> 15 <property name="maxWaitMillis" value="${spring.redis.maxWaitMillis}" /> 16 <property name="testOnBorrow" value="true" /> 17 <property name="testOnReturn" value="true" /> 18 </bean> 19 20 <bean id="jedisConnectionFactory" 21 class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" destroy-method="destroy"> 22 <property name="hostName" value="${spring.redis.hostName}"/> 23 <property name="port" value="${spring.redis.port}"/> 24 <!-- <property name="password" value="${redis_pwd}" /> --> 25 <property name="timeout" value="${spring.redis.timeout}"/> 26 <property name="usePool" value="true"/> 27 <property name="poolConfig" ref="jedisPoolConfig"/> 28 </bean>
现在, 我们有了Redis连接工厂, 接下来就可以使用Spring Data Redis模板了。
第二步:使用RedisTemplate
Redis连接工厂会生成到Redis数据库的连接(以RedisConnection的形式)。借助RedisConnection,可以存储和读取数据。例如,我们可以获取连接并使用它来保存一个问候信息,如下所示:
与之类似, 我们还可以使用RedisConnection来获取之前存储的问候信息:
毫无疑问, 这可以正常运行, 但是你难道真的愿意使用字节数组吗?
与其他的Spring Data项目类似, Spring Data Redis以模板的形式提供了较高等级的数据访问方案。 实际上,Spring Data Redis提供了两个模板:
RedisTemplate可以极大地简化Redis数据访问, 能够让我们持久化各种类型的key和value, 并不局限于字节数组。 在认识到key和value通常是String类型之后,StringRedisTemplate 扩展了RedisTemplate , 只关注String类型。
假设我们已经有了RedisConnectionFactory, 那么可以按照如下的方式构建RedisTemplate,xml方式:
1 <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"> 2 <property name="connectionFactory" ref="jedisConnectionFactory"/> 3 <property name="keySerializer"> 4 <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" /> 5 </property> 6 <property name="hashKeySerializer"> 7 <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" /> 8 </property> 9 </bean>
注解方式案例:
RedisTemplate
StringRedisTemplate
常用的方法:
这些子API中, 包含了很多从Redis中存取数据的方法。
第三步:使用RedisTemplate来操作Redis数据库
我们可以通过Service bean的方式来实现一个Redis数据库操作工具类,在这个工具类中依赖RedisTemplate,然后封装一些常用的操作方法,如图所示设计:
使用简单的值:
获取简单的值:
如果按照给定的key, 无法获得条目的话, 将会返回null。
这里只是用来启发大家的思路,后续的就快速过了,大家要有自己设计代码的能力,不能总是完全照搬别人的代码,那样对自己的能力提升是影响很大,要学会正确的站在巨人的肩膀上。
使用List类型的值:
使用List类型的value与之类似, 只需使用opsForList()方法即可。 例如, 我们可以在一个List类型的条目尾部添加一个值:
通过这种方式, 我们向列表的尾部添加了一个Product, 所使用的这个列表在存储时key为cart。 如果这个key尚未存在列表的话, 将会创建一个。
rightPush()会在列表的尾部添加一个元素, 而leftPush()则会在列表的头部添加一个值:
我们有很多方式从列表中获取元素, 可以通过leftPop()或rightPop()方法从列表中弹出一个元素:
除了从列表中获取值以外, 这两个方法还有一个副作用就是从列表中移除所弹出的元素。 如果你只是想获取值的话(甚至可能要在列表的中间获取) , 那么可以使用range()方法:
range()方法不会从列表中移除任何元素, 但是它会根据指定的key和索引范围, 获取范围内的一个或多个值。
从索引为2的元素到索引为12的元素(不包含) 。 如果范围超出了列表的边界, 那么只会返回索引在范围内的元素。 如果该索引范围内没有元素的话, 将会返回一个空的列表。
在Set上执行操作:
除了操作列表以外, 我们还可以使用opsForSet()操作Set。 最为常用的操作就是向Set中添加一个元素:
在我们有多个Set并填充值之后, 就可以对这些Set进行一些有意思的操作, 如获取其差异、 求交集和求并集:
当然, 我们还可以移除它的元素:
我们甚至还可以随机获取Set中的一个元素:
因为Set没有索引和内部的排序, 因此我们无法精准定位某个点, 然后从Set中获取元素。
绑定到某个key上 :
表格中包含了五个绑定key操作的api,它们能够以绑定key的方式执行操作。 这些子API与其他的API是对应的, 但是关注于某一个给定的key。
为了举例阐述这些子API的用法, 我们假设将Product对象保存到一个list中, 并且key为cart。 在这种场景下, 假设我们想从list的右侧弹出一个元素, 然后在list的尾部新增三个元素。 我们此时可以使用boundListOps()方法所返回的BoundListOperations:
注意, 我们只在一个地方使用了条目的key, 也就是调用boundListOps()的时候。 对返回的BoundListOperations执行的所有操作都会
应用到这个key上。
key和value的序列化器介绍
当某个条目保存到Redis key-value存储的时候, key和value都会使用Redis的序列化器(serializer) 进行序列化。 Spring Data Redis提供了多个这样的序列化器, 包括:
这些序列化器都实现了RedisSerializer接口, 如果其中没有符合需求的序列化器, 那么你还可以自行创建。
RedisTemplate会使用JdkSerializationRedisSerializer, 这意味着key和value都会通过Java进行序列
化。 StringRedisTemplate默认会使用StringRedis-Serializer, 这在我们的预料之中, 它实际上就是实现String与byte数组之
间的相互转换。 这些默认的设置适用于很多的场景, 但有时候你可能会发现使用一个不同的序列化器也是很有用处的。
例如, 假设当使用RedisTemplate的时候, 我们希望将Product类型的value序列化为JSON, 而key是String类
型。 RedisTemplate的setKeySerializer()和setValueSerializer()方法就需要如下所示:
在这里, 我们设置RedisTemplate在序列化key的时候, 使用StringRedisSerializer, 并且也设置了在序列化Product的时候, 使
用Jackson2JsonRedisSerializer。
xml配置方式上面已经有所展示。
小结
关系型数据库作为数据持久化领域唯一可选方案的时代已经一去不返了。 现在, 我们有多种不同的数据库, 每一种都代表了不同形式的数据,并提供了适应多种领域模型的功能。 Spring Data能够让我们在Spring应用中使用这些数据库, 并且使用一致的抽象方式访问各种数据库方案。
结束语:想要体面生活,又觉得打拼辛苦;想要健康身体,又无法坚持运动。人最失败的,莫过于对自己不负责任,连答应自己的事都办不到,又何必抱怨这个世界都和你作对?人生的道理很简单,你想要什么,就去付出足够的努力。
可爱博主:AlanLee
博客地址:http://www.cnblogs.com/AlanLee
本文出自博客园,欢迎大家加入博客园。