Jedis客户端已经比较易用了,不过在spring环境下,可能还需要简单的封装一下。
一、单节点Redis服务使用
即只有一个Redis server,或者在M-S模式下,只有Master提供读写服务时使用,配置中指定Master的IP和Port即可。此处使用了Spring FactoryBean方式来创建JedisPool实例。
1、SingletonClientFactoryBean.java
public class SingletonClientFactoryBean implements FactoryBean<JedisPool>,InitializingBean { private JedisPool jedisPool; private int maxTotal = 128; //最大空闲连接数 private int maxIdle = 2; //最小空闲连接数 private int minIdle = 1; //如果连接池耗尽,最大阻塞的时间,默认为6秒 private long maxWait = 6000;//单位毫秒 private String host; private int port; private int database = 0;//选择数据库,默认为0 private int timeout = 3000;//connectionTimeout,soTimeout,默认为30秒 private boolean testOnBorrow = true; private boolean testOnReturn = true; private String password; public void setMaxTotal(int maxTotal) { this.maxTotal = maxTotal; } public void setMaxIdle(int maxIdle) { this.maxIdle = maxIdle; } public void setMinIdle(int minIdle) { this.minIdle = minIdle; } public void setMaxWait(long maxWait) { this.maxWait = maxWait; } public void setHost(String host) { this.host = host; } public void setPort(int port) { this.port = port; } public void setDatabase(int database) { this.database = database; } public void setTimeout(int timeout) { this.timeout = timeout; } public void setTestOnBorrow(boolean testOnBorrow) { this.testOnBorrow = testOnBorrow; } public void setTestOnReturn(boolean testOnReturn) { this.testOnReturn = testOnReturn; } public void setPassword(String password) { this.password = password; } protected JedisPoolConfig buildConfig() { JedisPoolConfig config = new JedisPoolConfig(); config.setMinIdle(minIdle); config.setMaxIdle(maxIdle); config.setMaxTotal(maxTotal); config.setTestOnBorrow(testOnBorrow); config.setTestOnReturn(testOnReturn); config.setBlockWhenExhausted(true); config.setMaxWaitMillis(maxWait); config.setFairness(false); return config; } @Override public void afterPropertiesSet() throws Exception { JedisPoolConfig config = buildConfig(); jedisPool = new JedisPool(config,host,port,timeout, password, database,null); } @Override public JedisPool getObject() throws Exception { return jedisPool; } @Override public Class<?> getObjectType() { return JedisPool.class; } @Override public boolean isSingleton() { return true; } }
2、Spring.xml配置
<bean id="redisClient" class="com.demo.redis.spring.SingletonClientFactoryBean"> <property name="host" value="127.0.0.1"/> <property name="port" value="6379" /> <property name="maxTotal" value="256"/> <property name="maxIdle" value="8" /> <property name="maxWait" value="3000" /> <property name="timeout" value="3000" /> <property name="minIdle" value="2" /> </bean>
3、客户端使用
Jedis jedis = redisClient.getResource(); String cacheContent = null; try { cacheContent = jedis.get("hello_world"); }finally { redisClient.close(); } //获取redis数据之后,立即释放连接,然后开始进行业务处理 if(cacheContent == null) { //DB operation } //..
二、基于M-S模式下读写分离
通常情况下,Slave只是作为数据备份,不提供read操作,这种考虑是为了避免slave提供stale数据而导致一些问题。不过在很多场景下,即使slave数据有一定的延迟,我们仍然可以兼容或者正常处理,此时我们可以将slave提供read服务,并在M-S集群中将read操作分流,此时我们的Redis集群将可以支撑更高的QPS。
本文实例中,仅仅提供了“读写分离”的样板,尚未对所有的redis方法进行重写和封装,请开发者后续继续补充即可。此外,slave节点如果异常,我们应该支持failover,这一部分特性后续在扩展。
1、ReadWriteRedisClient.java
public class ReadWriteRedisClient implements InitializingBean { //master:port,slave:port,slave:port... //master first private String hosts; private JedisPool master; private List<JedisPool> slaves = new ArrayList<>(); private int maxTotal = 128; //最大空闲连接数 private int maxIdle = 2; //最小空闲连接数 private int minIdle = 1; //如果连接池耗尽,最大阻塞的时间,默认为6秒 private long maxWait = 6000;//单位毫秒 private int database = 0;//选择数据库,默认为0 private int timeout = 3000;//connectionTimeout,soTimeout,默认为30秒 private boolean testOnBorrow = true; private boolean testOnReturn = true; private String password; private Random random = new Random(); public void setMaxTotal(int maxTotal) { this.maxTotal = maxTotal; } public void setMaxIdle(int maxIdle) { this.maxIdle = maxIdle; } public void setMinIdle(int minIdle) { this.minIdle = minIdle; } public void setMaxWait(long maxWait) { this.maxWait = maxWait; } public void setDatabase(int database) { this.database = database; } public void setTimeout(int timeout) { this.timeout = timeout; } public void setTestOnBorrow(boolean testOnBorrow) { this.testOnBorrow = testOnBorrow; } public void setTestOnReturn(boolean testOnReturn) { this.testOnReturn = testOnReturn; } public void setPassword(String password) { this.password = password; } public void setHosts(String hosts) { this.hosts = hosts; } protected JedisPoolConfig buildConfig() { JedisPoolConfig config = new JedisPoolConfig(); config.setMinIdle(minIdle); config.setMaxIdle(maxIdle); config.setMaxTotal(maxTotal); config.setTestOnBorrow(testOnBorrow); config.setTestOnReturn(testOnReturn); config.setBlockWhenExhausted(true); config.setMaxWaitMillis(maxWait); config.setFairness(false); return config; } @Override public void afterPropertiesSet() throws Exception { JedisPoolConfig config = buildConfig(); String[] hostAndPorts = hosts.split(","); String masterHP = hostAndPorts[0]; String[] ms = masterHP.split(":"); master = new JedisPool(config,ms[0],Integer.valueOf(ms[1]),timeout, password, database,null); if(hostAndPorts.length > 1) { for(int i = 1; i < hostAndPorts.length; i++) { String[] ss = hostAndPorts[i].split(":"); JedisPool slave = new JedisPool(config,ss[0],Integer.valueOf(ss[1]),timeout, password, database,null); slaves.add(slave); } } slaves.add(master); } public String get(String key) { Jedis jedis = fetchResource(true); try { return jedis.get(key); } finally { jedis.close(); } } public List<String> mget(String... keys) { Jedis jedis = fetchResource(true); try { return jedis.mget(keys); } finally { jedis.close(); } } public String setex(String key,int seconds,String value) { Jedis jedis = fetchResource(false); try { return jedis.setex(key,seconds,value); } finally { jedis.close(); } } public Long setnx(String key,String value) { Jedis jedis = fetchResource(false); try { return jedis.setnx(key,value); } finally { jedis.close(); } } public String set(String key,String value) { Jedis jedis = fetchResource(false); try { return jedis.set(key,value); } finally { jedis.close(); } } public Long del(String key) { Jedis jedis = fetchResource(false); try { return jedis.del(key); } finally { jedis.close(); } } public Long expire(String key,int seconds) { Jedis jedis = fetchResource(false); try { return jedis.expire(key,seconds); } finally { jedis.close(); } } public Boolean exists(String key) { Jedis jedis = fetchResource(false); try { return jedis.exists(key); } finally { jedis.close(); } } public Long exists(String... keys) { Jedis jedis = fetchResource(false); try { return jedis.exists(keys); } finally { jedis.close(); } } private Jedis fetchResource(boolean read) { if(slaves.isEmpty() || !read) { return master.getResource(); } int size = slaves.size(); int i = random.nextInt(size); return slaves.get(i).getResource(); } public static void main(String[] args) throws Exception { String prefix = "_test_"; ReadWriteRedisClient client = new ReadWriteRedisClient(); client.setHosts("127.0.0.1:6379,127.0.0.1:6379"); client.afterPropertiesSet(); client.set(prefix + "10001","test"); System.out.println(client.get(prefix + "10001")); } }
2、Spring.xml配置
<bean id="readWriteRedisClient" class="com.demo.redis.spring.ReadWriteRedisClient"> <property name="hosts" value="127.0.0.1:6379,127.0.0.1:7379"/> <property name="maxTotal" value="256"/> <property name="maxIdle" value="8" /> <property name="maxWait" value="3000" /> <property name="timeout" value="3000" /> <property name="minIdle" value="2" /> </bean>
3、客户端使用
@Autowired private JedisPool redisClient; public void test() { Jedis jedis = redisClient.getResource(); //.. String cacheContent = null; try { cacheContent = readWriteRedisClient.get("hello_world"); } catch (Exception e) { //如果redis网络异常, 你可以选择重新抛出,或者忽略 } if(cacheContent == null) { //redis中不存在,或者异常 } }
三、基于Cluster模式的客户端
JedisCluster实例的简单封装,内部仍然基于连接池。需要注意,cluster模式下,mget等这种multi-keys操作将不再支持。其实我们无论如何封装,都无法非常合理的解决multi-keys问题,这里涉及到K-V在集群中的迁移、节点可用性、批量操作的异常处理,特别在异常处理时,如果某个key操作异常(可能对应的redis节点异常),那么其他已经操作成功的keys、或者后续尚未操作的keys该如何处理?这个答案是模糊不清的。此外,我们JAVA开发者通常会使用线程池 + Future机制来分解multi-keys操作,其实这会带来很大的性能隐患,不建议使用。
本人最终决定,保留redis Cluster的api方式,不做特殊封装,仅仅让其在spring环境中更易于使用即可。
1、ClusterClientFactoryBean.java
public class ClusterClientFactoryBean implements FactoryBean<JedisCluster>,InitializingBean { private JedisCluster jedisCluster; private int maxTotal = 128; //最大空闲连接数 private int maxIdle = 6; //最小空闲连接数 private int minIdle = 1; //如果连接池耗尽,最大阻塞的时间,默认为6秒 private long maxWait = 6000;//单位毫秒 private int timeout = 3000;//connectionTimeout,soTimeout,默认为3秒 private boolean testOnBorrow = true; private boolean testOnReturn = true; private String addresses;//ip:port;ip:port public void setMaxTotal(int maxTotal) { this.maxTotal = maxTotal; } public void setMaxIdle(int maxIdle) { this.maxIdle = maxIdle; } public void setMinIdle(int minIdle) { this.minIdle = minIdle; } public void setMaxWait(long maxWait) { this.maxWait = maxWait; } public void setTimeout(int timeout) { this.timeout = timeout; } public void setTestOnBorrow(boolean testOnBorrow) { this.testOnBorrow = testOnBorrow; } public void setTestOnReturn(boolean testOnReturn) { this.testOnReturn = testOnReturn; } public void setAddresses(String addresses) { this.addresses = addresses; } protected JedisPoolConfig buildConfig() { JedisPoolConfig config = new JedisPoolConfig(); config.setMinIdle(minIdle); config.setMaxIdle(maxIdle); config.setMaxTotal(maxTotal); config.setTestOnBorrow(testOnBorrow); config.setTestOnReturn(testOnReturn); config.setBlockWhenExhausted(true); config.setMaxWaitMillis(maxWait); config.setFairness(false); return config; } private Set<HostAndPort> buildHostAndPorts() { String[] hostPorts = addresses.split(","); Set<HostAndPort> hostAndPorts = new HashSet<>(); for(String item : hostPorts) { String[] hostPort = item.split(":"); HostAndPort hostAndPort = new HostAndPort(hostPort[0],Integer.valueOf(hostPort[1])); hostAndPorts.add(hostAndPort); } return hostAndPorts; } @Override public void afterPropertiesSet() throws Exception { JedisPoolConfig config = buildConfig(); Set<HostAndPort> hostAndPorts = buildHostAndPorts(); jedisCluster = new JedisCluster(hostAndPorts,timeout,config); } @Override public JedisCluster getObject() throws Exception { return jedisCluster; } @Override public Class<?> getObjectType() { return JedisCluster.class; } @Override public boolean isSingleton() { return true; } }
2、Spring.xml配置
<bean id="clusterRedisClient" class="com.demo.redis.spring.ClusterClientFactoryBean"> <property name="addresses" value="127.0.0.1:6379,127.0.01:7379,127.0.0.1:8379"/> <property name="maxTotal" value="256"/> <property name="maxIdle" value="8" /> <property name="maxWait" value="3000" /> <property name="timeout" value="3000" /> <property name="minIdle" value="2" /> </bean>
3、客户端使用
@Autowired private JedisCluster clusterRedisClient; public void test() { String cacheContent = null; try { cacheContent = clusterRedisClient.get("hello_world"); } catch (Exception e) { //如果异常,你可以决定是否忽略 } if(cacheContent == null) { //如果cache中不存在,或者redis异常 } }
相关推荐
Spring Data Redis中提供了一个高度封装的类:**RedisTemplate**,针对 Jedis 客户端中大量api进行了归类封装,将同一类型操作封装为operation接口,具体分类如下: - ValueOperations:简单K-V操作 - SetOperations...
Jedis Java操作Redis实例代码 向Redis保存对象、查询对象、代码封装 客户端连接资源管理 等等
jedis就是集成了redis的一些命令操作,封装了redis的java客户端。提供了连接池管理。一般不直接使用jedis,而是在其上在封装一层,作为业务的使用。如果用spring的话,可以看看spring 封装的 redis Spring Data ...
spring cloud gateway的负载均衡和动态路由的实现 demo_01,demo_02,demo_03 这三个服务相当于是集群的微服务 gateway这个服务是 spring...其中redis部分,有一个jar是自己封装的,可以自己手写redis工具类替换掉
MorningCheck-MongodbFramework 封装了Mongodb底层 MorningCheck-General-pojo 系统管理pojo 用户管理,角色管理,权限管理 MorningCheck-General-dao MorningCheck-School-pojo MorningCheck-School-dao ...
137 客户端与服务端通信-客户端封装 Ajax 请求2 138 客户端与服务端通信-解决跨域问题 139 Redis 为数据添加缓存-Redis HA 简介 140 Redis 为数据添加缓存-Redis Sentinel 高可用集群部署 141 Redis 为数据添加缓存-...
137 客户端与服务端通信-客户端封装 Ajax 请求2 138 客户端与服务端通信-解决跨域问题 139 Redis 为数据添加缓存-Redis HA 简介 140 Redis 为数据添加缓存-Redis Sentinel 高可用集群部署 141 Redis 为数据添加...
redis客户端 api与redis原生的命令几乎一一对应,redis集群情况,有些命令无法支持 redisson 3.5.7 redis客户端 高级api,将命令组合使用实现了一些功能。支持集群,其他高级功能。 dbutils 1.7 sql执行工具 对查询...
api测试工具为Postman,还用了mongodb客户端Robo 3T,redis客户端工具RedisDesktopManage 跑这个代码之前,需要准备好数据库,开启redis、mongodb、activeMQ服务。 需要注册自己的七牛云账号(上传头像)、秒嘀账号...
howsun-javaee-framework Java应用层框架 版本:1.0.8 ...5、封装了Redis客户端,取代Memcache 6、简化了Json操作 7、提供了分页、工具类封装的JSP标签库 8、大量工具包:如安全、Web、断言、编码等40多
├──cloud-service-reids──────────────Redis二次封装 ├──cloud-eureka-server──────────────服务注册中心[8761] ├──cloud-turbine-server─────────────断路器...
库存判断,利用decr操作(spring-data-redis封装后可以使用boundValueOps(KEY).increment(-1L)的形式 decr成功,发送mq消息,成功既可以返回客户端抢购成功 mq消费端处理下单、支付等具体流程(这里落db,支付等场景...
1. 项目介绍项目总体功能划分为核心组件包jason-kerner:包括常用的数据库封装,redis封装,oauth2客户端封装,swagger2封装,统一异常,输入,输入和web配置等微服务支撑模块jason-microservice-support:微服务的...
springboot 整合 redis,支持spring el 表达式。 springboot 整合 thymeleaf。 springboot 整合 logback。 netty rpc 实现原理。 开发环境 jdk 1.8 maven 3.5.3 dubbo 2.6.1 lombok 1.16.20 idea 2018 windows 7 ...
earth-frost是一个轻量级分布式任务调度框架。 介绍: 调度模块和执行模块分离 使用redis作为数据库 ...环境: Angular: v1.x JDK: 1.8+ ...frost-client 客户端api,第三方项目可依赖client实现与调度中心交互
java实现mqtt的发送和订阅,代码中有详细的注释,是分服务端和客户端来测试的,并有断开重连的处理!
RedissonAutoConfiguration 是 Spring Boot Redisson 的自动配置类,它封装了 Redisson 的配置和注入过程,让使用 Redisson 变得更加方便。 在 RedissonAutoConfiguration 中,它首先会检查当前应用所使用的 ...
系统功能完善(用户角色权限),此为框架平台,文档、注释齐全,专门供程序员二次开发 所有前端后台代码封装过后十分精简易上手,出错概率低。 同时支持移动客户端访问。 核心框架:Spring Boot 权限框架:Apache ...
IOIF以EXTJS为前端,以Spring、Struts、Hibernate为后端,整合了Proxool、Log4j、Quartz、Oscache、Castor、Memcached、redis等优秀的开源软件。 支持Tomcat6及Resin3等应用服务器,支持Oracle、MYSQL等数据库。IOIF...
IOIF以EXTJS为前端,以Spring、Struts、Hibernate为后端,整合了Proxool、Log4j、Quartz、Oscache、Castor、Memcached、redis等优秀的开源软件。 支持Tomcat6及Resin3等应用服务器,支持Oracle、MYSQL等数据库。IOIF...