本文原创,转载请注明:http://www.cnblogs.com/fengzheng/p/5941953.html
关于Redis集群搭建可以参考我的另一篇文章Redis集群搭建与简单使用
Redis是什么,能做什么
Redis是一个开源(BSD许可),内存存储的数据结构服务器,可用作数据库,高速缓存和消息队列代理。它支持字符串、哈希表、列表、集合、有序集合,位图,hyperloglogs等数据类型。内置复制、Lua脚本、LRU收回、事务以及不同级别磁盘持久化功能,同时通过RedisSentinel提供高可用,通过RedisCluster提供自动分区。(摘自Redis官网)
作为内存数据库,在现代互联网web系统中,还是主要将Redis作为缓存使用。大型互联网Web系统对性能要求很高,而在前端和数据层之间增加数据缓存已成为必不可少的手段之一,当前比较流行的两个技术就是Redis和Memcached,至于两者有什么区别,不是本文要说的内容。本文主要讲Javaweb如何操作Redis及Redis集群。
一般Java程序操作Redis
Redis提供了多种语言的客户端,在Java中最流行的是Jedis。访问可查看源码及使用方式。目前Jedis最新版本是2.9.0。无论是单机还是集群,Jedis都有很详细的说明和实例代码,这里只做简单说明。如果用Maven做包管理,需要引用jedis包,本例使用最新的2.9.0版本,如下:
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency>操作Redis单机
importredis.clients.jedis.Jedis; importredis.clients.jedis.JedisPool; importredis.clients.jedis.JedisPoolConfig; /** *Createdbyfengdezitaion2016/10/9. */ publicclassJedisClient{ privatestaticfinalStringhost="192.168.31.121"; privatestaticfinalJedisClientjedisClient=newJedisClient(); privateJedisjedis=null; /** *私有构造函数 */ privateJedisClient(){} publicstaticJedisClientgetInstance(){ returnjedisClient; } privateJedisPoolConfiggetPoolConfig(){ JedisPoolConfigjedisPoolConfig=newJedisPoolConfig(); jedisPoolConfig.setMaxIdle(10); jedisPoolConfig.setMaxTotal(100); jedisPoolConfig.setMaxWaitMillis(3000); returnjedisPoolConfig; } /** *添加 *@paramkey *@paramvalue *@return *@throwsException */ publicBooleanadd(Stringkey,Stringvalue)throwsException{ JedisPoolpool=newJedisPool(getPoolConfig(),host); Jedisjedis=null; try{ jedis=pool.getResource(); if(jedis.exists(key)){ thrownewException(String.format("key(%s)已存在",key)); } jedis.set(key,value); }catch(Exceptione){ throwe; } finally{ if(jedis!=null){ jedis.close(); } } pool.destroy(); returntrue; } /** *获取值 *@paramkey *@return *@throwsException */ publicStringget(Stringkey)throwsException{ JedisPoolpool=newJedisPool(getPoolConfig(),host); Jedisjedis=null; Stringresult=""; try{ jedis=pool.getResource(); result=jedis.get(key); }catch(Exceptione){ throwe; } finally{ if(jedis!=null){ jedis.close(); } } pool.destroy(); returnresult; } publicstaticvoidmain(String[]args){ JedisClientjedisClient=JedisClient.getInstance(); try{ /*Booleanresult=jedisClient.add("hello","redis1"); if(result){ System.out.println("success"); }*/ System.out.println(jedisClient.get("hello")); }catch(Exceptione){ e.printStackTrace(); } } }操作redis集群
importredis.clients.jedis.*; importjava.util.HashSet; importjava.util.Set; /** *Createdbyfengdezitaion2016/10/13. */ publicclassJedisClusterClient{ privatestaticintcount=0; privatestaticfinalJedisClusterClientredisClusterClient=newJedisClusterClient(); /** *私有构造函数 */ privateJedisClusterClient(){} publicstaticJedisClusterClientgetInstance(){ returnredisClusterClient; } privateJedisPoolConfiggetPoolConfig(){ JedisPoolConfigconfig=newJedisPoolConfig(); config.setMaxTotal(1000); config.setMaxIdle(100); config.setTestOnBorrow(true); returnconfig; } publicvoidSaveRedisCluster(){ Set<HostAndPort>jedisClusterNodes=newHashSet<HostAndPort>(); jedisClusterNodes.add(newHostAndPort("192.168.31.245",7000)); jedisClusterNodes.add(newHostAndPort("192.168.31.245",7001)); jedisClusterNodes.add(newHostAndPort("192.168.31.245",7002)); jedisClusterNodes.add(newHostAndPort("192.168.31.210",7003)); jedisClusterNodes.add(newHostAndPort("192.168.31.210",7004)); jedisClusterNodes.add(newHostAndPort("192.168.31.210",7005)); JedisClusterjc=newJedisCluster(jedisClusterNodes,getPoolConfig()); jc.set("cluster","thisisarediscluster"); Stringresult=jc.get("cluster"); System.out.println(result); } publicstaticvoidmain(String[]args){ JedisClusterClientjedisClusterClient=JedisClusterClient.getInstance(); jedisClusterClient.SaveRedisCluster(); } }Springmvc操作Redis
在Springmvc中操作Redis,首先当然要搭好Springmvc框架了。以下是在假设Springmvc环境已经架好的情况下。本例中Spring版本为4.3.2RELEASE。关于Spring的maven引用如下:
<!--spring版本号--> <spring.version>4.3.2.RELEASE</spring.version> <!--spring核心包--> <!--springframestart--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> <exclusions> <exclusion> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-oxm</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> <exclusions> <exclusion> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> </dependency> <!--springframeend-->操作Redis单机
只用Jedis自己实现注入(区别于下面的引用spring-data-redis)
把前面的JedisClient代码拿过来引用即可,只需实现一个访问Redis的Service,就可以集成到Springmvc。Service代码如下:
importorg.springframework.stereotype.Service; importutil.JedisClient; /** *Createdbyfengdezitaion2016/10/9. */ @Service publicclassRedisService{ publicStringget(Stringkey)throwsException{ JedisClientjedisClient=JedisClient.getInstance();//上面实现的JedisClient Stringresult=""; try{ result=jedisClient.get("hello"); }catch(Exceptione){ throwe; } returnresult; } }Controller实现如下:
@Controller @RequestMapping(value="redisAllInOne") publicclassRedisAllInOneController{ @Autowired privateRedisServiceredisService; @RequestMapping(value="get",method=RequestMethod.GET) @ResponseBody publicObjectgetByMyService(Stringkey){ try{ Stringresult=redisService.get(key); returnresult; }catch(Exceptione){ e.printStackTrace(); } returnnull; } }用spring-data-redis包做集成
上面是自己实现的注入,这里用spring-data-redis进行集成,只需简单配置即可,需要引用maven包如下,版本为目前最新版1.7.2.RELEASE:
<dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> <version>1.7.2.RELEASE</version> </dependency>使用spring-data-redis,即省去了自己实现注入的过程,通过它提供的一些配置,即可实现连接池配置、RedisTemplate配置、JedisConnectionFactory配置;通过JedisConnectionFactory可配置连接池参数、redis服务器、端口、密码、超时时间、database索引等;RedisTemplate即注入的bean,可以使用RedisTemplate自动注入的实体进行redis的一系列操作,具体看配置;
redis服务属性配置文件:
redis.maxIdle=300 redis.maxWait=3000 redis.testOnBorrow=true redis.host=192.168.31.121 redis.port=6379 redis.password=password redis.timeout=3000spring-data-redisxml配置文件redis-context.xml:
<!--jedis连接池配置--> <beanid="poolConfig"class="redis.clients.jedis.JedisPoolConfig"> <propertyname="maxIdle"value="${redis.maxIdle}"/> <propertyname="maxWaitMillis"value="${redis.maxWait}"/> <propertyname="testOnBorrow"value="${redis.testOnBorrow}"/> </bean> <!--redis服务器中心--> <beanid="connectionFactory"class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"> <propertyname="poolConfig"ref="poolConfig"/> <propertyname="port"value="${redis.port}"/> <propertyname="hostName"value="${redis.host}"/> <!--<propertyname="password"value="${redis.password}"/>--> <propertyname="timeout"value="${redis.timeout}"></property> <propertyname="database"value="1"></property> </bean> <beanid="commonRedisTemplate"class="org.springframework.data.redis.core.RedisTemplate"> <propertyname="connectionFactory"ref="connectionFactory"/> <propertyname="keySerializer"ref="stringRedisSerializer"/> <propertyname="hashKeySerializer"ref="stringRedisSerializer"/> <propertyname="valueSerializer"ref="stringRedisSerializer"/> <propertyname="hashValueSerializer"ref="stringRedisSerializer"/> </bean> <beanid="connectionFactory1"class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"> <propertyname="poolConfig"ref="poolConfig"/> <propertyname="port"value="${redis.port}"/> <propertyname="hostName"value="${redis.host}"/> <!--<propertyname="password"value="${redis.password}"/>--> <propertyname="timeout"value="${redis.timeout}"></property> <propertyname="database"value="2"></property> </bean> <beanid="stringRedisSerializer"class="org.springframework.data.redis.serializer.StringRedisSerializer"/> <beanid="cacheRedisTemplate"class="org.springframework.data.redis.core.RedisTemplate"> <propertyname="connectionFactory"ref="connectionFactory1"/> <propertyname="keySerializer"ref="stringRedisSerializer"/> <propertyname="hashKeySerializer"ref="stringRedisSerializer"/> <propertyname="valueSerializer"ref="stringRedisSerializer"/> <propertyname="hashValueSerializer"ref="stringRedisSerializer"/> </bean>之后在spring配置文件中引用以上文件:
<importresource="redis-context.xml"/>解释一下上面的配置:
poolConfig即配置redis连接池,之后配置了两个JedisConnectionFactory和RedisTemplate,一个RedisTemplate对应一个JedisConnectionFactory,这样可以配置根据场景配置不同的Redis连接,比如超时时间要求不一致、database0-15可以存储不同的数据等。这里就配置了database1和2,调用commonRedisTemplate会存到database1,调用cacheRedisTemplate会存到database2。
之后在Service层即可注入并引用这两个RedisTemplate,如下代码:
importorg.apache.commons.lang3.StringUtils; importorg.springframework.dao.DataAccessException; importorg.springframework.data.redis.connection.RedisConnection; importorg.springframework.data.redis.core.RedisCallback; importorg.springframework.data.redis.core.RedisTemplate; importorg.springframework.stereotype.Repository; importjavax.annotation.Resource; importjava.io.*; @Repository publicclassRedisCache{ @Resource(name="cacheRedisTemplate") privateRedisTemplate<String,String>cacheRedisTemplate; publicvoidput(Objectkey,Objectvalue){ if(null==value){ return; } if(valueinstanceofString){ if(StringUtils.isEmpty(value.toString())){ return; } } //TODOAuto-generatedmethodstub finalStringkeyf=key+""; finalObjectvaluef=value; finallongliveTime=86400; cacheRedisTemplate.execute(newRedisCallback<Long>(){ publicLongdoInRedis(RedisConnectionconnection) throwsDataAccessException{ byte[]keyb=keyf.getBytes(); byte[]valueb=toByteArray(valuef); connection.set(keyb,valueb); if(liveTime>0){ connection.expire(keyb,liveTime); } return1L; } }); } publicObjectget(Objectkey){ finalStringkeyf=(String)key; Objectobject; object=cacheRedisTemplate.execute(newRedisCallback<Object>(){ publicObjectdoInRedis(RedisConnectionconnection) throwsDataAccessException{ byte[]key=keyf.getBytes(); byte[]value=connection.get(key); if(value==null){ returnnull; } returntoObject(value); } }); returnobject; } /** *描述:<byte[]转Object>.<br> *<p> *<使用方法说明> *</p> * *@parambytes *@return */ privateObjecttoObject(byte[]bytes){ Objectobj=null; try{ ByteArrayInputStreambis=newByteArrayInputStream(bytes); ObjectInputStreamois=newObjectInputStream(bis); obj=ois.readObject(); ois.close(); bis.close(); }catch(IOExceptionex){ ex.printStackTrace(); }catch(ClassNotFoundExceptionex){ ex.printStackTrace(); } returnobj; } privatebyte[]toByteArray(Objectobj){ byte[]bytes=null; ByteArrayOutputStreambos=newByteArrayOutputStream(); try{ ObjectOutputStreamoos=newObjectOutputStream(bos); oos.writeObject(obj); oos.flush(); bytes=bos.toByteArray(); oos.close(); bos.close(); }catch(IOExceptionex){ ex.printStackTrace(); } returnbytes; } }最后在Controller中调用即可
@Autowired privateRedisCacheredisCache; @RequestMapping(value="get",method=RequestMethod.GET) @ResponseBody publicObjectgetByMyService(Stringkey){ try{ Stringresult=redisService.get(key); returnresult; }catch(Exceptione){ e.printStackTrace(); } returnnull; } @RequestMapping(value="save",method=RequestMethod.GET) @ResponseBody publicObjectsave(){ Tokentoken=newToken(); token.setAccess_token("token"); token.setExpires_in(1000); try{ redisCache.put("token",token); }catch(Exceptione){ e.printStackTrace(); } return"ok"; }操作Redis集群
只用Jedis自己实现注入(区别于下面的引用spring-data-redis)
把前面的JedisClusterClient代码拿过来引用即可,只需实现一个访问Redis的Service,就可以集成到Springmvc。Service代码如下:
importorg.springframework.stereotype.Service; importutil.JedisClusterClient; /** *Createdbyfengdezitaion2016/10/13. */ @Service publicclassRedisClusterService{ publicvoidsave()throwsException{ //调用JedisClusterClient中的方法 JedisClusterClientjedisClusterClient=JedisClusterClient.getInstance(); try{ jedisClusterClient.SaveRedisCluster(); }catch(Exceptione){ throwe; } } }最后在Controller中调用实现的Service即可
@Controller @RequestMapping(value="redisCluster") publicclassRedisClusterController{ @Autowired privateRedisClusterServiceredisClusterService; @RequestMapping(value="save",method=RequestMethod.GET) @ResponseBody publicObjectsave(){ try{ redisClusterService.save(); }catch(Exceptione){ e.printStackTrace(); returnString.format("error:%s",e.getMessage()); } return"ok"; } }用spring-data-redis包做集成
Spring和spring-data-redismaven包引用和前面一致,之所以引用spring-data-redis1.7.2.RELEASE,是因为目前只有这个最新版本才支持集群操作。
redis集群服务属性配置
redis.maxIdle=300 redis.maxWait=3000 redis.testOnBorrow=false redis.timeout=3000spring-data-redisxml集群配置文件redis-cluster-context.xml
<!--连接池配置--> <beanid="poolConfig"class="redis.clients.jedis.JedisPoolConfig"> <propertyname="maxIdle"value="${redis.maxIdle}"/> <propertyname="maxWaitMillis"value="${redis.maxWait}"/> <propertyname="testOnBorrow"value="${redis.testOnBorrow}"/> </bean> <beanid="redisClusterConfig"class="org.springframework.data.redis.connection.RedisClusterConfiguration"> <propertyname="maxRedirects"value="3"></property> <propertyname="clusterNodes"> <set> <beanclass="org.springframework.data.redis.connection.RedisNode"> <constructor-argname="host"value="192.168.31.245"></constructor-arg> <constructor-argname="port"value="7000"></constructor-arg> </bean> <beanclass="org.springframework.data.redis.connection.RedisNode"> <constructor-argname="host"value="192.168.31.245"></constructor-arg> <constructor-argname="port"value="7001"></constructor-arg> </bean> <beanclass="org.springframework.data.redis.connection.RedisNode"> <constructor-argname="host"value="192.168.31.245"></constructor-arg> <constructor-argname="port"value="7002"></constructor-arg> </bean> <beanclass="org.springframework.data.redis.connection.RedisNode"> <constructor-argname="host"value="192.168.31.210"></constructor-arg> <constructor-argname="port"value="7003"></constructor-arg> </bean> <beanclass="org.springframework.data.redis.connection.RedisNode"> <constructor-argname="host"value="192.168.31.210"></constructor-arg> <constructor-argname="port"value="7004"></constructor-arg> </bean> <beanclass="org.springframework.data.redis.connection.RedisNode"> <constructor-argname="host"value="192.168.31.210"></constructor-arg> <constructor-argname="port"value="7005"></constructor-arg> </bean> </set> </property> </bean> <beanid="redis4CacheConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"> <constructor-argname="clusterConfig"ref="redisClusterConfig"/> <propertyname="timeout"value="${redis.timeout}"/> <propertyname="poolConfig"ref="poolConfig"/> </bean> <beanname="stringRedisSerializer"class="org.springframework.data.redis.serializer.StringRedisSerializer"/> <beanid="clusterRedisTemplate"class="org.springframework.data.redis.core.RedisTemplate"> <propertyname="connectionFactory"ref="redis4CacheConnectionFactory"/> <propertyname="keySerializer"ref="stringRedisSerializer"/> <propertyname="hashKeySerializer"ref="stringRedisSerializer"/> <propertyname="valueSerializer"ref="stringRedisSerializer"/> <propertyname="hashValueSerializer"ref="stringRedisSerializer"/> </bean>之后在Spring配置文件中引用
<importresource="redis-cluster-context.xml"/>解释以上配置:
poolConfig是连接池配置,redisClusterConfig配置了Redis集群的各个节点(节点host和port最好写在属性配置文件中),集群搭建可见我的另一篇博客。然后下面和单机配置一样了,一对JedisConnectionFactory和RedisTemplate。
之后在Service层即可注入并引用这个RedisTemplate,代码如下:
importorg.apache.commons.lang3.StringUtils; importorg.springframework.beans.factory.annotation.Autowired; importorg.springframework.dao.DataAccessException; importorg.springframework.data.redis.connection.RedisConnection; importorg.springframework.data.redis.core.RedisCallback; importorg.springframework.data.redis.core.RedisTemplate; importorg.springframework.stereotype.Repository; importjava.io.*; /** *Createdbyfengdezitaion2016/9/29. */ @Repository publicclassRedisClusterCache{ @Autowired privateRedisTemplateclusterRedisTemplate; publicvoidput(Objectkey,Objectvalue){ if(null==value){ return; } if(valueinstanceofString){ if(StringUtils.isEmpty(value.toString())){ return; } } //TODOAuto-generatedmethodstub finalStringkeyf=key+""; finalObjectvaluef=value; finallongliveTime=86400; clusterRedisTemplate.execute(newRedisCallback<Long>(){ publicLongdoInRedis(RedisConnectionconnection) throwsDataAccessException{ byte[]keyb=keyf.getBytes(); byte[]valueb=toByteArray(valuef); connection.set(keyb,valueb); if(liveTime>0){ connection.expire(keyb,liveTime); } return1L; } }); } publicObjectget(Objectkey){ finalStringkeyf=(String)key; Objectobject; object=clusterRedisTemplate.execute(newRedisCallback<Object>(){ publicObjectdoInRedis(RedisConnectionconnection) throwsDataAccessException{ byte[]key=keyf.getBytes(); byte[]value=connection.get(key); if(value==null){ returnnull; } returntoObject(value); } }); returnobject; } /** *描述:<byte[]转Object>.<br> *<p> *<使用方法说明> *</p> * *@parambytes *@return */ privateObjecttoObject(byte[]bytes){ Objectobj=null; try{ ByteArrayInputStreambis=newByteArrayInputStream(bytes); ObjectInputStreamois=newObjectInputStream(bis); obj=ois.readObject(); ois.close(); bis.close(); }catch(IOExceptionex){ ex.printStackTrace(); }catch(ClassNotFoundExceptionex){ ex.printStackTrace(); } returnobj; } privatebyte[]toByteArray(Objectobj){ byte[]bytes=null; ByteArrayOutputStreambos=newByteArrayOutputStream(); try{ ObjectOutputStreamoos=newObjectOutputStream(bos); oos.writeObject(obj); oos.flush(); bytes=bos.toByteArray(); oos.close(); bos.close(); }catch(IOExceptionex){ ex.printStackTrace(); } returnbytes; } }最后在Controller中调用即可
@Controller @RequestMapping(value="redisCluster") publicclassRedisClusterController{ @Autowired privateRedisClusterCacheredisClusterCache; @RequestMapping(value="clusterSave",method={RequestMethod.GET,RequestMethod.POST}) @ResponseBody publicObjectclusterSave(){ //redisClusterCache.put("cluster","savecluster"); Tokentoken=newToken(); token.setExpires_in(1000); token.setAccess_token("helloworld"); redisClusterCache.put("token",token); return"ok"; } @RequestMapping(value="getKey",method=RequestMethod.GET) @ResponseBody publicObjectgetCluster(Stringkey){ Objectval=redisClusterCache.get(key); returnval; } }注意事项:
版本问题,如果用spring-data-redis做集成操作Reids集群,只有spring-data-redis目前最新版本1.7才包含对集群的操作,而最新的spring-data-redis中的某些功能对Springmvc的版本也有些限制,所以尽量选择高版本的Springmvc对应。 如果存储的value值是一个实体对象,那么一定要实现Serializable接口本文内容总结:
原文链接:https://www.cnblogs.com/fengzheng/p/5941953.html