Spring-Data-Redis使用总结

Redis

Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它能够用做数据库、缓存和消息中间件. 它支持多种类型的数据结构。html

Redis3.0+ 版本开始支持集群java

Redis支持的数据类型

字符串(strings)git

散列(hashes)github

列表(lists)redis

集合(sets)spring

有序集合(sorted sets)数据库

Redis应用场景

数据缓存express

并发控制(分布式锁)编程

发布订阅(Pus/Sub)windows

消息队列

HttpSession共享

登陆

Redis核心配置文件

redis.conf(windows版本下叫redis.windows.conf)

运行时配置更改

Redis容许在运行的过程当中,在不重启服务器的状况下更改服务器配置,同时也支持 使用特殊的CONFIG SET和 CONFIG GET命令用编程方式查询并设置配置。

并不是全部的配置指令都支持这种使用方式,可是大部分是支持的。更多相关的信息请查阅CONFIG SET和 CONFIG GET页面。

须要确保的是在经过CONFIG SET命令进行的设置的同时,也需在 redis.conf文件中进行了相应的更改。 将来Redis有计划提供一个CONFIG REWRITE命令在不更改现有配置文件的同时, 根据当下的服务器配置对redis.conf文件进行重写。

配置参数项详解:http://www.runoob.com/redis/redis-conf.html

Redis官方网站:http://redis.io/

Redis中文社区:http://redis.cn/

Spring Data Redis

spring-data-redis 1.5新特性

支持redis中HyperLogLog 

RedisSerializers基于jackson

支持配置redis集群

spring-data-redis 1.6新特性

支持 ZRANGEBYLEX 命令

ZSET 操做范围负无穷到正无穷

RedisCache性能改进

通用Jackson2序列化、反序列化

spring-data-redis须要

jdk1.6+

spring3.2.8+

redis2.8+(or redis latest 2.6 )

RedisTemplate

ValueOperations 对字符串操做
ListOperations 对List集合操做
SetOperations 对Set集合操做
ZSetOperations 对有序set操做
HashOperations 对Hash集合操做
HyperLogLogOperations 对HyperLogLog操做

并发控制(分布式锁) 

// 若是没有设置进行设置
redisTemplate.opsForValue().setIfAbsent(key, value);
// 给key设置过时时间,避免死锁
redisTemplate.expire(key, timeout, unit);

 

redis事务

Redis 事务能够一次执行多个命令, 而且带有如下两个重要的保证:

  • 事务是一个单独的隔离操做:事务中的全部命令都会序列化、按顺序地执行。事务在执行的过程当中,不会被其余客户端发送来的命令请求所打断。
  • 事务是一个原子操做:事务中的命令要么所有被执行,要么所有都不执行。

一个事务从开始到执行会经历如下三个阶段:

  • 开始事务。
  • 命令入队。
  • 执行事务。
public void multi() {
    long start = System.currentTimeMillis();
    List result = redisTemplate.execute(new SessionCallback>() {
		@Override
		public  List execute(RedisOperations operations) throws DataAccessException {
			operations.multi();
			for (int i = 0; i < 100000; i++) {
				String key = "key" + i;
				String value = "value" + i;
				redisTemplate.opsForValue().set(key, value);
			}
			return operations.exec();
		}
	});
    long end = System.currentTimeMillis();
	System.out.println("result:" + result + ",millis:" + (end - start));
}

Transactional

支持事务注解

redisTemplate.setEnableTransactionSupport(true);

redis管道

Redis管道一样是打开管道,一次性向redis服务端发送命令,最后关闭管道,可是它跟事务是有区别的,Redis管道只是减小了链接消耗,并不具有事务的特性,它会进行一次性提交和一次性响应,成功的命令会执行,失败的跳过,最终一次性返回结果。

使用Redis管道技术在批量发送redis命令的状况下比较适用,能够极大的提供执行效率。

public void pipelined() {
		long start = System.currentTimeMillis();
		stringRedisTemplate.executePipelined(new RedisCallback() {
			public Object doInRedis(RedisConnection connection) throws DataAccessException {
				StringRedisConnection stringRedisConn = (StringRedisConnection) connection;
				for (int i = 0; i < 100000; i++) {
                    stringRedisConn.set("key" + i, "value" + i);
				}
				return null;
			}
		});
		long end = System.currentTimeMillis();
		System.out.println("millis:" + (end - start));
	}

Redis脚本(lua脚本)

Redis和lua都是基于C语言实现的,因此Redis中采用内置lua脚本解释器,来支持lua脚本,lua很小。

目前还不是特别理解Redis脚本的使用场景,我的感受相似关系型数据库中存储过程的概念。

如下是一段java调用redis执行lua脚本的代码示例:

java:

public void redisLuaScript() {
		DefaultRedisScript redisScript = new DefaultRedisScript();
		ClassPathResource resource = new ClassPathResource("/redisScript/demo.lua");
		redisScript.setScriptSource(new ResourceScriptSource(resource));
		redisScript.setResultType(String.class);
		List keys = new ArrayList();
		keys.add("mykey1");
		keys.add("mykey2");
		String result = redisTemplate.execute(redisScript, keys, new Object[] { "123", "456" });
		System.out.println(result);
	}

lua:KEYS对应在lua脚本中要操做的redis键,ARGV对应java传递进来的参数值

if redis.call('GET', KEYS[1]) == false
then redis.call('SET', KEYS[1], ARGV[1])
end
if redis.call('GET', KEYS[2]) == false
then redis.call('SET', KEYS[2], ARGV[2])
end
return "ok"

Spring Data Redis 对 java 集合的支持

SDR封装了经过调用java原生的集合操做Redis数据类型,下降了在java中操做Redis数据类型的复杂度,同时也使得java原生集合支持分布式

@Resource(name = "deque")
private Deque deque;
@Resource(name = "map")
private Map map;
	
@Test
public void redisQueue() {
	deque.push("test1");
}
	
@Test
public void redisMap(){
	map.put("key1", "v1");
}

Spring Data Redis 对 Spring Cache 的支持

spring cache 是一个spring缓存组件,spring3.1之后提供了Spring  cache缓存抽象,和其余spring组件同样,例如spring事务等,采用注解驱动的方式,利用Spring AOP(动态代理)结合XML Schema来实现,采用这用方式对代码的侵入性极小,是一种轻量级的缓存抽象。

SDR对SpringCache提供支持,将原有的基于JVM容器的缓存,采用基于Redis缓存中间件来完成,实现了分布式缓存。

<cache:annotation-driven />
<bean id="cacheManager" class="org.springframework.data.redis.cache.RedisCacheManager">
	<constructor-arg ref="redisTemplate" />
</bean>
@Cacheable(value = "userCache",condition="#mobile ne null and #mobile ne ''",unless = "#result eq '' or #result eq null")
@Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
@Override
public User getUserByMobile(String mobile) {
	System.out.println("execute getUserByMobile start...");
	User user = userDao.getUserByMobile(mobile);
	System.out.println("execute getUserByMobile end...");
	return user;
}

spring cache支持 SpEL语法

SpEL语法详见官方介绍:http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#expressions

@Cacheable triggers cache population
@CacheEvict triggers cache eviction
@CachePut updates the cache without interfering with the method execution
@Caching regroups multiple cache operations to be applied on a method
@CacheConfig shares some common cache-related settings at class-level

@Cacheable 

应用于方法上,若是存在缓存值则直接返回,若是不存在缓存则向下执行实际方法,

value参数,Redis中ZSET集合的键

condition参数,对传入参数的筛选

unless参数,对返回结果的筛选

@CacheEvict

用于缓存发生变化时,对以前的缓存进行收回

@CachePut

更新缓存,执行实际的方法

@Caching

容许嵌套多个@Cacheable 、@CacheEvict、@CachePut

@Caching(evict = { @CacheEvict("primary"), @CacheEvict(cacheNames="secondary", key="#p0") })

@CacheConfig

缓存配置注解,这是一个类级别的注解,对缓存键的统一管理

@Service("userService")
@CacheConfig(cacheNames="userCache")
public class UserServiceImpl implements UserServices {

	@Resource(name = "userDao")
	private UserDao userDao;

	@Cacheable(condition="#mobile ne null and #mobile ne ''",unless = "#result eq '' or #result eq null")
	@Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
	@Override
	public User getUserByMobile(String mobile) {
		System.out.println("execute getUserByMobile start...");
		User user = userDao.getUserByMobile(mobile);
		System.out.println("execute getUserByMobile end...");
		return user;
	}
}

Redis发布订阅

redisTemplate.convertAndSend("demo:message", "This is a new message...");
<!-- redis订阅 -->	
	<bean id="messageListener"
		class="org.springframework.data.redis.listener.adapter.MessageListenerAdapter">
		 <property name="delegate">
		 	<bean id="demoListener" class="com.demo.lisenter.DemoListener" />
		 </property>
        <property name="serializer" ref="jdkSerializer" />
	</bean>

	<bean id="redisContainer"
		class="org.springframework.data.redis.listener.RedisMessageListenerContainer">
		<property name="connectionFactory" ref="jedisConnectionFactory" />
		<property name="messageListeners">
			<map>
				<entry key-ref="messageListener">
					<bean class="org.springframework.data.redis.listener.ChannelTopic">
						<constructor-arg value="demo:message" />
					</bean>
				</entry>
			</map>
		</property>
	</bean>

Redis Sentinel 

Redis Sentinel 是Redis自2.8+之后Redis自身提供的高可用解决方案

Redis Sentinel提供任务监控、预警通知、自动故障转移

在配置Redis Sentinel以前须要先配置Redis主从

一、在从库的redis.conf文件中增长以下配置:

# slaveof  <masterip> <masterport>

slaveof 10.200.0.102 6379

二、sentinel.conf

port 26379
daemonize yes
sentinel monitor mymaster 10.200.0.102 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 900000

三、使用Spring Data Redis 链接 Redis Sentinel

<!-- redis哨兵-->
	<bean id="sentinelConfig"
		class="org.springframework.data.redis.connection.RedisSentinelConfiguration">
		<property name="master">
			<bean class="org.springframework.data.redis.connection.RedisNode">
				<property name="name" value="mymaster" />
			</bean>
		</property>
		<property name="sentinels">
			<set>
				<bean class="org.springframework.data.redis.connection.RedisNode">
					<constructor-arg name="host" value="10.200.0.102" />
					<constructor-arg name="port" value="26379" />
				</bean>
				<bean class="org.springframework.data.redis.connection.RedisNode">
					<constructor-arg name="host" value="10.200.0.102" />
					<constructor-arg name="port" value="26380" />
				</bean>
			</set>
		</property>
	</bean>
	<bean id="jedisConnectionFactory"
		class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
		<constructor-arg ref="sentinelConfig" />
	</bean>

测试 Redis Sentinel 自动故障切换

程序经过Redis Sentinel 链接到Redis主库6379

中止6379

src/redis-cli shutdown

自动切换至6380

在这个过程当中,Redis会自动修改sentinel.conf和redis.conf

 

参考资料:http://docs.spring.io/spring-data/redis/docs/1.7.1.RELEASE/reference/html/

配套代码:https://github.com/chenjunlong/spring-data-redis

相关文章
相关标签/搜索