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

相關文章
相關標籤/搜索