Spring客户端对Redis 缓存的使用(Java客户端等Redis3.X RedisCluster模式的支持)
来源:互联网 发布:2017网络营销发展数据 编辑:程序博客网 时间:2024/05/16 12:43
最近项目中使用Spring并使用Redis作为缓存,参考网上的一些做法。发现Spring根本启动不了,先贴出网上的做法:
导入包
<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来规避此问题。
- Spring客户端对Redis 缓存的使用(Java客户端等Redis3.X RedisCluster模式的支持)
- Redis的java客户端(jedis)配置(spring)与使用
- Redis的java客户端(jedis)配置(spring)与使用
- Redis的java客户端(jedis)配置(spring)与使用
- 使用Redis的jedis客户端整合spring
- 一个支持集群版 redis3.0 的客户端例子
- redis客户端的使用
- Redis的java客户端Jedis的使用
- redis的Java客户端jedis使用示例
- 使用Redis的Java客户端Jedis
- 使用Redis的Java客户端Jedis
- 使用Redis的Java客户端Jedis
- 使用Redis的Java客户端Jedis
- 使用Redis的Java客户端Jedis
- Redis集群 Java客户端Jedis的使用
- 如何使用redis的java客户端
- 使用redis的java客户端-----jedis
- C#客户端Redis服务器的分布式缓存
- 解读开源js函数的收获
- loadrunner 多台压力机并发
- 总结:SVN与GIT的区别
- CentOS 6.5下yum安装 MySQL-5.5全过程图文教程
- Spring Boot 官方文档学习(一)入门及使用
- Spring客户端对Redis 缓存的使用(Java客户端等Redis3.X RedisCluster模式的支持)
- 字符串 String
- Z-Stack Developer's Guide - Binding & Routing
- mysql select into outfile 语法 乱码问题
- rabbitmq client 自编译
- spring框架学习(八)—静态代理、JDK与CGLIB动态代理、AOP+IoC
- 常用机器学习算法总结
- Spring Security3 - MVC 整合教程 (初识Spring Security3)
- HTML5