文档章节

使用Spring Data Redis操作Redis(一)

secondriver
 secondriver
发布于 2015/09/17 09:26
字数 1988
阅读 499
收藏 9

   Spring-Data-Redis项目(简称SDR)对Redis的Key-Value数据存储操作提供了更高层次的抽象,类似于Spring Framework对JDBC支持一样。

   项目主页:http://projects.spring.io/spring-data-redis/

   项目文档:http://docs.spring.io/spring-data/redis/docs/1.5.0.RELEASE/reference/html/

 

   本文主要介绍Spring Data Redis的实际使用。  

 

   1.Spring Data Redis 1.5新特性

     增加了Redis HyperLogLog命令PFADD,PFCOUNT,PFMERGE

     可以使用Jackson基于RedisSerializer对Java类型序列化

     使用PropertySource配置Redis Sentinel连接,目前仅Jedis客户端支持


   2.Spring Data Redis ?

     Spring Data Redis使得在Spring应用中读写Redis数据库更加容易。

     Spring Data Redis提供了四种Redis服务的Java客户端包的集成,分别是Jedis, JRedis, SRP and Lettuce 


   3.版本要求

     Spring Data Redis1.2.x要求JDK1.6+,Spring Framwork3.2.8+

     Key-Value存储服务Redis 2.6.x+


   4.搭建环境

     本文假设已经安装完成了Redis服务,并成功运行。

     创建maven项目,添加依赖的Jar,本文主要使用jedis

     

<dependency>
			<groupId>org.springframework.data</groupId>
			<artifactId>spring-data-redis</artifactId>
			<version>1.5.0.RELEASE</version>
		</dependency>
<dependency>
			<groupId>redis.clients</groupId>
			<artifactId>jedis</artifactId>
			<version>2.6.2</version>
		</dependency>


  5.连接Redis服务


    在Spring Data Redis中通过org.springframework.data.redis.connection包中的RedisConnection和RedisConnectionFactory类来获取Redis连接。

    

   5.1配置JedisConnectionFactory

   

<?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"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

  <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" p:host-name="server" p:port="6379" />

</beans>

 

   5.2配置Jredis,SRP,Lettuce的配置和上面配置类似,只需要配置对应的RedisConnectionFactory接口实现接口,它门位于如下包中:

      wKioL1Ubt1_QGYshAACQYxKlF9c690.jpg


   5.3关于RedisConnectionFactory注意问题

   上面四种连接器并不是都支持Redis的所有特性,它们之间有差异性,如果调用方法在Connection API中不支持则抛出“UnsupportedOperationException”异常,具体情况需要了解对应的Redis Java客户端Jar的实现。


   5.4关于Redis Sentinel(这里暂称为:哨兵)支持

   Redis Sentinel监听主服务,再主服务发生故障时能够切换至从服务,将从服务升为主服务来保证故障恢复,使用该功能需要在JedisConnectionFactory设置RedisSentinelConfiguration属性,目前Jedis对Redis Sentinel提供支持。


  编码方式如下:

  

public RedisConnectionFactory jedisConnectionFactory() {
  RedisSentinelConfiguration sentinelConfig = new RedisSentinelConfiguration() .master("mymaster")
  .sentinel("127.0.0.1", 26379) .sentinel("127.0.0.1", 26380);
  return new JedisConnectionFactory(sentinelConfig);
}


  在Spring容器中配置:

 

<bean id="sentinelConfig"
		class="org.springframework.data.redis.connection.RedisSentinelConfiguration">
		<constructor-arg name="master" value="mymaster" />
		<constructor-arg name="sentinelHostAndPorts">
			<set>
				<value>192.168.88.153:26379</value>
				<value>192.168.88.153:26380</value>
				<value>192.168.88.153:26382</value>
			</set>
		</constructor-arg>
	</bean>
	
	<bean id="jedisConnectionFactory"
		class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
		<constructor-arg ref="sentinelConfig" />
	</bean>


   注意:在配置Redis的sentinel.conf文件时注意使用外部可以访问的ip地址,因为当redis-sentinel服务和redis-server在同一台机器的时候,主服务发生变化时配置文件中将主服务ip变为127.0.0.1,这样外部就无法访问了。如果应用程序,Redis服务在同一台机器则不存在这样的隐患,具体情况则更加实际的网络环境。


 配置好之后,在实例化JedisConnectionFactory之后,可见如下日志:

 

2015-4-1 17:29:30 redis.clients.jedis.JedisSentinelPool initSentinels
信息: Trying to find master from available Sentinels...
2015-4-1 17:29:30 redis.clients.jedis.JedisSentinelPool initSentinels
信息: Redis master running at 192.168.88.153:6384, starting Sentinel listeners...
2015-4-1 17:29:30 redis.clients.jedis.JedisSentinelPool initPool
信息: Created JedisPool to master at 192.168.88.153:6384

 实验环境中192.168.88.153:6384的Redis实例是主服务。

 

 5.5下面通过一组代码展示具体使用

     

@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class TestJedis {

	public static ApplicationContext ctx;

	public static JedisConnectionFactory jedisConnetionFactory;

	public JedisConnection jedisConnection;

	@SuppressWarnings("unchecked")
	@BeforeClass
	public static void setBeforeClass() {
		ctx = new ClassPathXmlApplicationContext("spring-redis.xml");
		jedisConnetionFactory = (JedisConnectionFactory) ctx
				.getBean("jedisConnectionFactory");
	}

	@Before
	public void setBefore() {
		jedisConnection = jedisConnetionFactory.getConnection();
	}

	@After
	public void setAfter() {
		jedisConnection.close();
	}

	private void print(Collection<RedisServer> c) {
		for (Iterator<RedisServer> iter = c.iterator(); iter.hasNext();) {
			RedisServer rs = (RedisServer) iter.next();
			System.out.println(rs.getHost() + ":" + rs.getPort());
		}
	}

	// 简单测试JedisConnection
	@Ignore
	@Test
	public void test1() {
		if (!jedisConnection.exists(new String("zz").getBytes())) {
			jedisConnection.set(new String("zz").getBytes(),
					new String("zz").getBytes());
		}
	}

	@Ignore
	@Test
	public void test2() {
		Set<byte[]> keys = jedisConnection.keys(new String("*").getBytes());
		for (Iterator<byte[]> iter = keys.iterator(); iter.hasNext();) {
			System.out.println(new String(iter.next()));
		}
	}

	// 测试Sentinel
	@Ignore
	@Test
	public void test3() throws InterruptedException {
		if (jedisConnetionFactory.getSentinelConnection().isOpen()) {
			Collection<RedisServer> c = jedisConnetionFactory
					.getSentinelConnection().masters();
			print(c);
			RedisNode rn = new RedisNode("192.168.88.153", 6380);
			rn.setName("mymaster");
			c = jedisConnetionFactory.getSentinelConnection().slaves(rn);
			print(c);
		}

		for (int i = 0; i < 1000; i++) {
			jedisConnection.set(new String("k" + i).getBytes(), new String("v"
					+ i).getBytes());
			Thread.sleep(1000);
		}
		Set<byte[]> keys = jedisConnection.keys(new String("k*").getBytes());
		Assert.assertEquals(1000, keys.size());
	}
}


  6.RedisTemplate支持


   熟悉Spring的JdbcTemplate对象的话,应该大概能猜出来RedisTemplate的作用了,RedisTemplate对象对RedisConnection进行了封装,它提供了连接管理,序列化等功能,它对Redis的交互进行了更高层次的抽象。另外还提供了Redis操作命令的操作视图,这极大的方便和简化了Redis的操作。


   下表是具体的操作视图接口类介绍:

 

Key类型操作
ValueOperations Redis String/Value 操作
ListOperations Redis List 操作
SetOperations Redis Set 操作
ZSetOperations Redis Sort Set 操作
HashOperations Redis Hash 操作
Value约束操作
BoundValueOperations Redis String/Value key 约束
BoundListOperations Redis List key 约束
BoundSetOperations Redis Set key 约束
BoundZSetOperations Redis Sort Set key 约束
BoundHashOperations Redis Hash key 约束

   在org.springframework.data.redis.core包中对表中的接口都提供了相应的默认实现。


  6.1RedisSerializer

    Spring Data Redis提供了对Key-Value的序列号,在使用RedisTemplate对象是默认使用JdkSerializationRedisSerializer实现。还提供了其它的序列化实现如:Jackson2JsonRedisSerializer,JacksonJsonRedisSerializer,GenericToStringSerializer,StringRedisSerializer,OxmSerializer。

   另外用户可以提供自己的序列化实现

 

 6.2配置RedisTemplate

   

<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"
		p:connection-factory-ref="jedisConnectionFactory" />
	<bean id="stringRedisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">
		<property name="connectionFactory" ref="jedisConnectionFactory" />
	</bean>

 

   这里配置了RedisTemplate和StringRedisTemplate,不同之处在于StringRedisTemplate的Key-Value序列化使用的是StringRedisSerializer。使用StringRedisTemplate操作Redis之后的结果是读友好的。

另外对Hash类型而言,还有对应的HashKey序列化(其对应于Hash类型的字段名)。


6.3RedisTemplate的使用

  

// 测试RedisTemplate,自主处理key的可读性(String序列号)
	@Ignore
	@Test
	public void test4() {
		String key = "spring";
		ListOperations<String, String> lop = redisTemplate.opsForList();
		RedisSerializer<String> serializer = new StringRedisSerializer();
		redisTemplate.setKeySerializer(serializer);
		redisTemplate.setValueSerializer(serializer);
		// rt.setDefaultSerializer(serializer);

		lop.leftPush(key, "aaa");
		lop.leftPush(key, "bbb");
		long size = lop.size(key); // rt.boundListOps(key).size();
		Assert.assertEquals(2, size);
	}

	// 测试便捷对象StringRedisTemplate
	@Ignore
	@Test
	public void test5() {
		ValueOperations<String, String> vop = stringRedisTemplate.opsForValue();
		String key = "string_redis_template";
		String v = "use StringRedisTemplate set k v";
		vop.set(key, v);
		String value = vop.get(key);
		Assert.assertEquals(v, value);
	}

 

   具体使用那种序列化策略则更加存储的Key-Value内容做权衡即可。


   通过RedisTemplate中的方法的参数RedisCallback回调接口来获取RedisConnection,进一步操作Redis,比如事务控制。需要注意的是如果使用StringRedisTemplate则返回的是StringRedisConnection对象。


   测试RedisCallback代码示例:

   

// 测试Callback
	@Ignore
	@Test
	public void test61() {
		Long dbsize = (Long) stringRedisTemplate
				.execute(new RedisCallback<Object>() {
					@Override
					public Long doInRedis(RedisConnection connection)
							throws DataAccessException {
						StringRedisConnection stringRedisConnection=(StringRedisConnection)connection;
						return stringRedisConnection.dbSize();
					}
				});
		System.out.println("dbsize:" + dbsize);
	}

  

   测试SessionCallback代码示例:

  

@Test
	public void test62() {
		List<Object> txresult = stringRedisTemplate
				.execute(new SessionCallback<List<Object>>() {

					@Override
					public List<Object> execute(RedisOperations operations)
							throws DataAccessException {
						operations.multi();
						operations.opsForHash().put("hkey", "multikey4",
								"multivalue4");
						operations.opsForHash().get("hkey", "k1");

						return operations.exec();
					}

				});
		for (Object o : txresult) {
			System.out.println(o);
			/**
			 * 0. false/true 
			 * 1. v1
			 */
		}
	}

   说明:

  •  在事务中的操作返回都是null,因此不能在execute中对操作的结果进行处理。比如这里get("hkey","k1")的结果。

  •  Hash操作中如果字段存在则返回false(redis中是0),不存在返回true(redis中是1)与字段对应的值是否更新无关联。

  • exec()方法返回List<Object>中的对象对应事务中执行的每条命令的返回结果。

 

 7.执行Lua脚本

   Redis中执行Lua脚本开发思路:http://aiilive.blog.51cto.com/1925756/1626372

   Spring Data Redis中执行Lua脚本更加便利,下面示例展示使用RedisTemplate对象执行Lua脚本。

      

// 测试Lua脚本
	@Ignore
	@Test
	public void test71() {
		List<String> keys = new ArrayList<String>();
		RedisScript<Long> script = new DefaultRedisScript<Long>(
				"local size = redis.call('dbsize'); return size;", Long.class);
		Long dbsize = stringRedisTemplate
				.execute(script, keys, new Object[] {});
		System.out.println("sha1:" + script.getSha1());
		System.out.println("Lua:" + script.getScriptAsString());
		System.out.println("dbsize:" + dbsize);
	}

	@Test
	public void test72() {
		DefaultRedisScript<Boolean> script = new DefaultRedisScript<Boolean>();
		/**
		 * isexistskey.lua内容如下:
		 * 
		 * return tonumber(redis.call("exists",KEYS[1])) == 1;
		 */
		script.setScriptSource(new ResourceScriptSource(new ClassPathResource(
				"/isexistskey.lua")));

		script.setResultType(Boolean.class);// Must Set

		System.out.println("script:" + script.getScriptAsString());
		Boolean isExist = stringRedisTemplate.execute(script,
				Collections.singletonList("k2"), new Object[] {});
		Assert.assertTrue(isExist);
	}


 8.支持类操作

   在org.springframework.data.redis.support包中提供了各种可重用组件,这些组件可以应用到Redis存储,如atomic计数,JDK集合,Redis的类型集合(RedisList,RedisSet等)

      

<redis:collection id="springList" key="springlist"
		template="stringRedisTemplate" type="LIST" />

   

@Ignore
	@Test
	public void test8() {
		RedisAtomicInteger rai = new RedisAtomicInteger("redis:atomic",
				jedisConnetionFactory);
		System.out.println(rai.get());
	}

	// 测试Redis Collection
	@Ignore
	@Test
	public void test9() {
		@SuppressWarnings("unchecked")
		RedisList<String> redisList = (RedisList<String>) ctx
				.getBean("springList");
		redisList.clear();
		redisList.addFirst("china");
		redisList.add("in");
		redisList.add("go");
		redisList.addLast("made");
		System.out.println(redisList.getKey());
	}

   

本文出自 “野马红尘” 博客,转载请与作者联系!

© 著作权归作者所有

secondriver
粉丝 10
博文 229
码字总数 233821
作品 0
广州
程序员
私信 提问
Spring Data Redis与Jedis的选择(转)

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

easonjim
2017/11/08
0
0
技术专题讨论:如何对 JPA 或者 MyBatis 进行技术选型

在我们平时的项目中,大家都知道可以使用 JPA 或者 Mybatis 作为 ORM 层。对 JPA 和 Mybatis 如何进行技术选型? 下面看看大精华总结如下: 最佳回答 首先表达个人观点,JPA必然是首选的。 ...

后海
2018/06/27
1K
0
Springdata RedisTemplate 操作redis 使用 Jackson2JsonRedisSerializer反序列化数据错误问题

项目使用的 Springdata RedisTemplate 操作redis 使用 Jackson2JsonRedisSerializer序列化数据 数据库持久层使用jpa,Product与ProductCategory是关联关系 上图是序列化后在redis中存储的数据...

风夏li
2018/11/24
2.9K
2
Spring集成Redis方案(spring-data-redis)(基于Jedis的单机模式)(待实践)

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

easonjim
2017/10/05
0
0
redis(三)与spring整合

一、 JAVA操作redis通常使用的是Jedis,通过java代码来操作redis的数据存储读取等操作,用过的人应该知道,Jedis客户端已经足够简单和轻量级了,但是呢,在此同时,Spring也为Redis提供了支持...

废柴
2018/07/11
223
0

没有更多内容

加载失败,请刷新页面

加载更多

JAVA 编写redisUtils工具类,防止高并发获取缓存出现并发问题

import lombok.extern.slf4j.Slf4j;import org.springframework.data.redis.core.BoundHashOperations;import org.springframework.data.redis.core.BoundValueOperations;import org.......

huangkejie
31分钟前
5
0
JMM内存模型(一)&volatile关键字的可见性

在说这个之前,我想先说一下计算机的内存模型: CPU在执行的时候,肯定要有数据,而数据在内存中放着呢,这里的内存就是计算机的物理内存,刚开始还好,但是随着技术的发展,CPU处理的速度越...

走向人生巅峰的大路
48分钟前
91
0
你对AJAX认知有多少(2)?

接着昨日内容,我们几天继续探讨ajax的相关知识点 提到ajax下面几个问题又是必须要了解的啦~~~ 8、在浏览器端如何得到服务器端响应的XML数据。 通过XMLHttpRequest对象的responseXMl属性 9、 ...

理性思考
58分钟前
4
0
正则表达式基础(一)

1.转义 转义的作用: 当某个字符在表达式中具有特殊含义,例如字符串引号中出现了引号,为了可以使用这些字符本身,而不是使用其在表达式中的特殊含义,则需要通过转义符“\”来构建该字符转...

清自以敬
今天
4
0
idea中@Data标签getset不起作用

背景:换电脑以后在idea中有@data注解都不生效 解决办法:idea装个插件 https://blog.csdn.net/seapeak007/article/details/72911529...

栾小糖
今天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部