- 即,Java语言连接redis服务
步骤
- 导包
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency>
- 连接
@Test public void testConnect() { Jedis jedis = new Jedis("119.23.64.216", 6379); String value = jedis.get("key"); System.out.println(value); jedis.close(); }
- 通过Jedis池获取Jedis
JedisPoolConfig config = new JedisPoolConfig(); // Jedis的配置 config.setMaxTotal(maxTotal); // 最大连接数 config.setMaxIdle(maxIdle); // 最大空闲数 JedisPool jedisPool = new JedisPool(config, host, port); Jedis jedis = jedisPool.getResource(); ... jedis.close();
案例:服务调用次数控制
- 设定A、B、C三个用户,A用户限制10次/分调用,B用户限制20次/分调用,C用户限制30次/分调用
- Jedis 获取类
public class JedisUtils { private static JedisPool jedisPool = null; private static String host = null; private static int port; private static int maxTotal = 30; // 最大连接数 private static int maxIdle = 10; // 最大空闲数 static { ResourceBundle redis = ResourceBundle.getBundle("redis"); host = redis.getString("host"); port = Integer.parseInt(redis.getString("port")); try { maxTotal = Integer.parseInt(redis.getString("maxTotal")); } catch (MissingResourceException e) { e.printStackTrace(); } try { maxIdle = Integer.parseInt(redis.getString("maxIdle")); } catch (MissingResourceException e) { e.printStackTrace(); } JedisPoolConfig config = new JedisPoolConfig(); config.setMaxTotal(maxTotal); config.setMaxIdle(maxIdle); jedisPool = new JedisPool(config, host, port); } public static Jedis getJedis() { return jedisPool.getResource(); } }
# 配置文件 redis.properties host=119.23.64.216 port=6379 maxTotal=30 maxIdle=10
- 服务接口
public interface Service { void service(); }
- 服务接口的实现方法
public class CountService implements Service { private int maxTime; // 最大次数 private int id; // 用户id private int liveSeconds; // 限制的单位时间 public CountService() { } public CountService(int maxTime, int id, int liveSeconds) { this.maxTime = maxTime; this.id = id; this.liveSeconds = liveSeconds; } @Override public void service() { try (Jedis jedis = JedisUtils.getJedis()) { // 这个代码会出现bug,当刚好检测到还有数据,但数据已经超出范围的时候,跳过了setex一步;到了incr的时候,如果突然数据到时间了,消失了,就会出现num从1开始的情况。 // 因此,只能在incr之后,做一个判断,判断当前数值是否异常。 String value = jedis.get("id:" + id); if (value == null) { jedis.setex("id:" + id, liveSeconds, String.valueOf(Long.MAX_VALUE - maxTime)); } try { Long num = jedis.incr("id:" + id); // 判断是否异常,如果异常,就直接重新set一次 if (num < Long.MAX_VALUE - maxTime) { jedis.setex("id:" + id, liveSeconds, String.valueOf(Long.MAX_VALUE - maxTime)); num = jedis.incr("id:" + id); } business(maxTime - (Long.MAX_VALUE - num)); } catch (JedisDataException e) { System.out.println("使用已经到达次数上限,请升级会员级别"); } } } private void business(long val) { System.out.println("执行" + id + "的第" + val + "次业务"); } }
Runnable
实现方法。Service以组合的方式进入方法,降低耦合,可以装配不同的Service实现类。public class ServiceTask implements Runnable { private Service service; private static final Random random = new Random(); public ServiceTask() { } public ServiceTask(Service service) { this.service = service; } @Override public void run() { while (true) { service.service(); try { Thread.sleep(100 + random.nextInt(20)); } catch (InterruptedException e) { e.printStackTrace(); } } } }
- 调用。切记:多线程不能用junit测试!
public class ServiceTest { public static void main(String[] args) { ExecutorService threadPool = Executors.newCachedThreadPool(); threadPool.execute(new ServiceTask(new CountService(10, 1, 60))); threadPool.execute(new ServiceTask(new CountService(20, 2, 60))); threadPool.execute(new ServiceTask(new CountService(30, 3, 60))); threadPool.shutdown(); } }