Spring客户端对Redis 缓存的使用(Java客户端等Redis3.X RedisCluster模式的支持)
2016-09-29 15:06
791 查看
最近项目中使用Spring并使用Redis作为缓存,参考网上的一些做法。发现Spring根本启动不了,先贴出网上的做法:
导入包
配置核心类
完成如上配置后就是在业务逻辑层的注解配置:
@Cacheable(key=”#id”,value=”student”),这个注释的意思是,当调用这个方法的时候,会从一个名叫 accountCache 的缓存中查询,如果没有,则执行实际的方法(即查询数据库),并将执行的结果存入缓存中,否则返回缓存中的对象。这里的缓存中的 key 就是参数 id
@CacheEvict 注释来标记要清空缓存的方法,当这个方法被调用后,即会清空缓存。注意其中一个
@CachePut 注释,这个注释可以确保方法被执行,同时方法的返回值也被记录到缓存中,实现缓存与数据库的同步更新。
我们不难看出,缓存的key为方法参数的一部分,为了避免两个数据其实不一样但方法参数有可能一致的情况我们需要自定义缓存的key来避免。
如上是通过注解在方法级别来配置缓存。现在我们来自定义操作缓存,即手动管理缓存中的数据:
redis缓存工具类
ValueOperations ——基本数据类型和实体类的缓存
ListOperations ——list的缓存
SetOperations ——set的缓存
HashOperations ——Map的缓存
Java对Redis Cluster模式的支持
查阅相关资料Spring-data-redis在1.7版本的时候才开始执行Redis Cluster模式。不知道是不是Redis3.X必须要求的,现在要配置Spring对Redis的操作必须配置RedisClusterConfiguration。
现在目前主要有二种方式:
一、以直接调用jedis来实现;
二、使用spring-data-redis 1.7X版本
下面分别对这二种方式如何操作Redis进行说明:
使用Spring-data-redis:
Redis Cluster调试中常见错误
(1) 按如上配置启动服务时,抛出ERR This instance has cluster support disabled.此时由于redis未开启Redis Cluster。在配置中设置cluster-enabled即可。
(1)当客户端与集群服务器不在同一台服务器上时,有如下错误Could not get a resource from the Cluster
(2)操作Redis时报Too many cluster redirections
JedisCluster(Set jedisClusterNode, int timeout, int maxRedirections) ;
JedisCluster jc = new JedisCluster(jedisClusterNodes,5000,1000);
请参考:https://gitHub.com/xetorthio/jedis/issues/659
(3)Redis Cluster数据写入慢
检查在通过./redis-trib命令建立集群时,如果是通过127.0.0.1的方式建立的集群,那么在往Redis Cluster中写入数据时写入速度比较慢。可以通过配置真实的IP来规避此问题。
导入包
<dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> <version>{version}/version> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>{version}</version> </dependency>
配置核心类
@Bean public JedisConnectionFactory redisConnectionFactory() { JedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory(); redisConnectionFactory.setUsePool(false); redisConnectionFactory.setHostName(xxx); redisConnectionFactory.setPort(xxx); return redisConnectionFactory; } @Bean public RedisTemplate<String, String> redisTemplate(JedisConnectionFactory jf) { RedisTemplate<String, String> redisTemplate = new RedisTemplate<String, String>(); redisTemplate.setConnectionFactory(jf); return redisTemplate; } @Bean(name="redisCacheManager") public CacheManager cacheManager(RedisTemplate redisTemplate) { RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate); // Number of seconds before expiration. Defaults to unlimited (0) cacheManager.setDefaultExpiration(3000); // Sets the default expire time // (in seconds) return cacheManager; }
完成如上配置后就是在业务逻辑层的注解配置:
@CachePut(key="#student.id",value="student") @Override public void add(Student student) { //xxxx } @CacheEvict(value="student",key="#id") public void delete(Integer id) { //xxx } @Cacheable(key="#id",value="student") @Override public Student queryById(Integer id) { //xxx }
@Cacheable(key=”#id”,value=”student”),这个注释的意思是,当调用这个方法的时候,会从一个名叫 accountCache 的缓存中查询,如果没有,则执行实际的方法(即查询数据库),并将执行的结果存入缓存中,否则返回缓存中的对象。这里的缓存中的 key 就是参数 id
@CacheEvict 注释来标记要清空缓存的方法,当这个方法被调用后,即会清空缓存。注意其中一个
@CachePut 注释,这个注释可以确保方法被执行,同时方法的返回值也被记录到缓存中,实现缓存与数据库的同步更新。
我们不难看出,缓存的key为方法参数的一部分,为了避免两个数据其实不一样但方法参数有可能一致的情况我们需要自定义缓存的key来避免。
@Bean public KeyGenerator wiselyKeyGenerator(){ return new KeyGenerator() { @Override public Object generate(Object target, Method method, Object... params) { StringBuilder sb = new StringBuilder(); sb.append(target.getClass().getName()); sb.append(method.getName()); for (Object obj : params) { sb.append(obj.toString()); } return sb.toString(); } }; } @Cacheable(value = "usercache",keyGenerator = "wiselyKeyGenerator")
如上是通过注解在方法级别来配置缓存。现在我们来自定义操作缓存,即手动管理缓存中的数据:
redis缓存工具类
ValueOperations ——基本数据类型和实体类的缓存
ListOperations ——list的缓存
SetOperations ——set的缓存
HashOperations ——Map的缓存
@Autowired @Qualifier("jedisTemplate") public RedisTemplate redisTemplate; /** * 缓存基本的对象,Integer、String、实体类等 * @param key 缓存的键值 * @param value 缓存的值 * @return 缓存的对象 */ public <T> ValueOperations<String,T> setCacheObject(String key,T value) { ValueOperations<String,T> operation = redisTemplate.opsForValue(); operation.set(key,value); return operation; } /** * 获得缓存的基本对象。 * @param key 缓存键值 * @param operation * @return 缓存键值对应的数据 */ public <T> T getCacheObject(String key/*,ValueOperations<String,T> operation*/) { ValueOperations<String,T> operation = redisTemplate.opsForValue(); return operation.get(key); } /** * 缓存List数据 * @param key 缓存的键值 * @param dataList 待缓存的List数据 * @return 缓存的对象 */ public <T> ListOperations<String, T> setCacheList(String key,List<T> dataList) { ListOperations listOperation = redisTemplate.opsForList(); if(null != dataList) { int size = dataList.size(); for(int i = 0; i < size ; i ++) { listOperation.rightPush(key,dataList.get(i)); } } return listOperation; } /** * 获得缓存的list对象 * @param key 缓存的键值 * @return 缓存键值对应的数据 */ public <T> List<T> getCacheList(String key) { List<T> dataList = new ArrayList<T>(); ListOperations<String,T> listOperation = redisTemplate.opsForList(); Long size = listOperation.size(key); for(int i = 0 ; i < size ; i ++) { dataList.add((T) listOperation.leftPop(key)); } return dataList; } /** * 缓存Set * @param key 缓存键值 * @param dataSet 缓存的数据 * @return 缓存数据的对象 */ public <T> BoundSetOperations<String,T> setCacheSet(String key,Set<T> dataSet) { BoundSetOperations<String,T> setOperation = redisTemplate.boundSetOps(key); /*T[] t = (T[]) dataSet.toArray(); setOperation.add(t);*/ Iterator<T> it = dataSet.iterator(); while(it.hasNext()) { setOperation.add(it.next()); } return setOperation; } /** * 获得缓存的set * @param key * @param operation * @return */ public Set<T> getCacheSet(String key/*,BoundSetOperations<String,T> operation*/) { Set<T> dataSet = new HashSet<T>(); BoundSetOperations<String,T> operation = redisTemplate.boundSetOps(key); Long size = operation.size(); for(int i = 0 ; i < size ; i++) { dataSet.add(operation.pop()); } return dataSet; } /** * 缓存Map * @param key * @param dataMap * @return */ public <T> HashOperations<String,String,T> setCacheMap(String key,Map<String,T> dataMap) { HashOperations hashOperations = redisTemplate.opsForHash(); if(null != dataMap) { for (Map.Entry<String, T> entry : dataMap.entrySet()) { /*System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue()); */ hashOperations.put(key,entry.getKey(),entry.getValue()); } } return hashOperations; } /** * 获得缓存的Map * @param key * @param hashOperation * @return */ public <T> Map<String,T> getCacheMap(String key/*,HashOperations<String,String,T> hashOperation*/) { Map<String, T> map = redisTemplate.opsForHash().entries(key); /*Map<String, T> map = hashOperation.entries(key);*/ return map; } /** * 缓存Map * @param key * @param dataMap * @return */ public <T> HashOperations<String,Integer,T> setCacheIntegerMap(String key,Map<Integer,T> dataMap) { HashOperations hashOperations = redisTemplate.opsForHash(); if(null != dataMap) { for (Map.Entry<Integer, T> entry : dataMap.entrySet()) { /*System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue()); */ hashOperations.put(key,entry.getKey(),entry.getValue()); } } return hashOperations; } /** * 获得缓存的Map * @param key * @param hashOperation * @return */ public <T> Map<Integer,T> getCacheIntegerMap(String key/*,HashOperations<String,String,T> hashOperation*/) { Map<Integer, T> map = redisTemplate.opsForHash().entries(key); /*Map<String, T> map = hashOperation.entries(key);*/ return map; }
Java对Redis Cluster模式的支持
查阅相关资料Spring-data-redis在1.7版本的时候才开始执行Redis Cluster模式。不知道是不是Redis3.X必须要求的,现在要配置Spring对Redis的操作必须配置RedisClusterConfiguration。
现在目前主要有二种方式:
一、以直接调用jedis来实现;
二、使用spring-data-redis 1.7X版本
下面分别对这二种方式如何操作Redis进行说明:
// 通过Jedis操作Redis Cluster的模型可以参考Redis官网,具体如下: Set<HostAndPort> jedisClusterNodes = new HashSet<HostAndPort>(); //Jedis Cluster will attempt to discover cluster nodes automatically jedisClusterNodes.add(new HostAndPort("10.96.5.183",9001)); jedisClusterNodes.add(new HostAndPort("10.96.5.183",9002)); jedisClusterNodes.add(new HostAndPort("10.96.5.183",9003)); JedisCluster jc = new JedisCluster(jedisClusterNodes);
使用Spring-data-redis:
@Bean public RedisClusterConfiguration getRedisCluster() { Set<RedisNode> jedisClusterNodes = new HashSet<RedisNode>(); // Jedis Cluster will attempt to discover cluster nodes automatically jedisClusterNodes.add(new RedisNode(redisHostName, Integer.valueOf(redisPort))); //jedisClusterNodes.add( xxx ); RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration(); redisClusterConfiguration.setClusterNodes( new HashSet<RedisNode>()); return redisClusterConfiguration; } @Bean public JedisConnectionFactory jedisConnectionFactory() { JedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory(getRedisCluster()); /* * Defaults redisConnectionFactory.setUsePool(false); redisConnectionFactory.setHostName(redisHostName); redisConnectionFactory.setPort(Integer.valueOf(redisPort)); * */ return redisConnectionFactory; } @Bean public RedisTemplate<String, String> redisTemplate(JedisConnectionFactory cf) { RedisTemplate<String, String> redisTemplate = new RedisTemplate<String, String>(); redisTemplate.setConnectionFactory(cf); return redisTemplate; }
Redis Cluster调试中常见错误
(1) 按如上配置启动服务时,抛出ERR This instance has cluster support disabled.此时由于redis未开启Redis Cluster。在配置中设置cluster-enabled即可。
(1)当客户端与集群服务器不在同一台服务器上时,有如下错误Could not get a resource from the Cluster
一般当客户端与集群服务器在同一台服务器上时,操作Redis Cluster正常; 当二者不在同一台服务器上时报如上错误,可能是clusterTimeOut时间设置过小;
(2)操作Redis时报Too many cluster redirections
初始化JedisCluster时,设定JedisCluster的maxRedirections.
JedisCluster(Set jedisClusterNode, int timeout, int maxRedirections) ;
JedisCluster jc = new JedisCluster(jedisClusterNodes,5000,1000);
请参考:https://gitHub.com/xetorthio/jedis/issues/659
(3)Redis Cluster数据写入慢
检查在通过./redis-trib命令建立集群时,如果是通过127.0.0.1的方式建立的集群,那么在往Redis Cluster中写入数据时写入速度比较慢。可以通过配置真实的IP来规避此问题。
相关文章推荐
- Redis的java客户端(jedis)配置(spring)与使用
- 使用 Spring缓存抽象 支持 EhCache 和 Redis 混合部署
- Spring Boot中的缓存支持(二)使用Redis做集中式缓存
- Redis的java客户端(jedis)配置(spring)与使用
- Spring Boot中的缓存支持(二)使用Redis做集中式缓存
- (转)使用 Spring缓存抽象 支持 EhCache 和 Redis 混合部署
- 《partner4java 讲述Spring入门》之:spring cache支持(spring3.1如何使用cache 缓存)
- Spring Boot中的缓存支持(二)使用Redis做集中式缓存
- Spring Boot中的缓存支持(二)使用Redis做集中式缓存
- 使用Spring Data +Redis实现缓存
- spring+hibernate 二级缓存 配置+java使用实例
- 使用Redis的Java客户端Jedis
- 深入理解Spring Redis的使用 (二)、RedisTemplate事务支持、序列化
- Java对观察者模式的支持——Observer和ObServable的使用
- 【Java/Android性能优 4】PreloadDataCache支持预取的数据缓存,使用简单,支持多种缓存算法,支持不同网络类型,扩展性强
- 使用java客户端调用redis
- JedisCluster 客户端集成到Spring,java代码中的使用
- 使用Redis的Java客户端Jedis
- 使用java和shell脚本支持GUI模式/CLI模式切换
- 【Java/Android性能优5】 Android ImageCache图片缓存,使用简单,支持预取,支持多种缓存算法,支持不同网络类型,扩展性强