Jedis的使用

 

一、简介

Jedis是支持事务、管道和集成了Redis的一些命令操作的Java客户端。提供了连接池管理,对redis数据的操作。但一般不直接使用jedis,而是再封装一层,作为业务的使用。

官方文档

一、使用

启动redis,默认端口6379,非本机连接需修改配置文件

# 不绑定,接受所有IP的连接请求
# bind 127.0.0.1

# 关闭保护模式
protected-mode no

放行6379端口

iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 6379 -j ACCEPT
# 保存配置
service iptables save

1.单机环境

新建个连接池类

//连接池对象
private static JedisPool pool;

//最大连接数
private static Integer maxTotal = 20;

//在jedispool中最大的idle状态(空闲的)的jedis实例的个数
private static Integer maxIdle = 20;

//在jedispool中最小的idle状态(空闲的)的jedis实例的个数
private static Integer minIdle = 20;

//获得jedis实例的时候是否要进行验证操作,如果赋值true。则得到的jedis实例肯定是可以用的。
private static Boolean testOnBorrow = true;

//在归还jedis实例的时候是否要进行验证操作,如果赋值true。则放回l的jedis实例肯定是可以用的。
private static Boolean testOnReturn = true;

private static String redisIp = "192.168.8.10";
private static Integer redisPort = 6379;

/**
 * 初始化连接池
 */
private static void initPool() {
    JedisPoolConfig config = new JedisPoolConfig();
    config.setMaxTotal(maxTotal);
    config.setMaxIdle(maxIdle);
    config.setMinIdle(minIdle);
    config.setTestOnBorrow(testOnBorrow);
    config.setTestOnReturn(testOnReturn);
    //连接耗尽的时候,是否阻塞,false会抛出异常,true阻塞直到超时。默认为true。
    config.setBlockWhenExhausted(true);
    pool = new JedisPool(config, redisIp, redisPort, 1000 * 2);
}

static {
    initPool();
}

//获取连接对象
public static Jedis getJedis() {
    return pool.getResource();
}

//归还连接对象
public static void returnResource(Jedis jedis) {
    //todo close
    jedis.close();
}

//测试
public static void main(String[] args) {
    Jedis jedis = pool.getResource();
    jedis.set("kekeke", "veveveveve");
    returnResource(jedis);
    pool.destroy();//销毁连接池中的所有连接
    System.out.println("end");
}

img

方便使用再封装一个工具类

//设置key的有效期,单位秒
public static Long expire(String key, int exTime) {
    Jedis jedis = null;
    Long result = null;
    try {
        jedis = RedisPool.getJedis();
        result = jedis.expire(key, exTime);
    } catch (Exception e) {
        e.printStackTrace();
        RedisPool.returnResource(jedis);
        return result;
    }
    RedisPool.returnResource(jedis);
    return result;
}

//添加key-value时同时设置有效期,单位秒
public static String setEx(String key, String value, int exTime) {
    Jedis jedis = null;
    String result = null;
    try {
        jedis = RedisPool.getJedis();
        result = jedis.setex(key, exTime, value);
    } catch (Exception e) {
        e.printStackTrace();
        RedisPool.returnResource(jedis);
        return result;
    }
    RedisPool.returnResource(jedis);
    return result;
}

//添加永久key-value
public static String set(String key, String value) {
    Jedis jedis = null;
    String result = null;
    try {
        jedis = RedisPool.getJedis();
        result = jedis.set(key, value);
    } catch (Exception e) {
        e.printStackTrace();
        RedisPool.returnResource(jedis);
        return result;
    }
    RedisPool.returnResource(jedis);
    return result;
}

//获取值
public static String get(String key) {
    Jedis jedis = null;
    String result = null;
    try {
        jedis = RedisPool.getJedis();
        result = jedis.get(key);
    } catch (Exception e) {
        e.printStackTrace();
        RedisPool.returnResource(jedis);
        return result;
    }
    RedisPool.returnResource(jedis);
    return result;
}

//删除key-value
public static Long del(String key) {
    Jedis jedis = null;
    Long result = null;
    try {
        jedis = RedisPool.getJedis();
        result = jedis.del(key);
    } catch (Exception e) {
        e.printStackTrace();
        RedisPool.returnResource(jedis);
        return result;
    }
    RedisPool.returnResource(jedis);
    return result;
}

//测试
public static void main(String[] args) {
    RedisPoolUtil.setEx("keyex", "valuex", 60 * 10);
    String value = RedisPoolUtil.get("keyex");
    System.out.println(value);
    System.out.println("end");
}

管道和事物

// Transactions,事务方式,监听一些key的值是否改变来决定是否执行
public static void jedisTransactions() {
    Jedis jedis = RedisPool.getJedis();
    long start = System.currentTimeMillis();
    Transaction tx = jedis.multi();
    for (int i = 0; i < 100000; i++) {
        tx.set("t" + i, "t" + i);
    }
    //监听,其值改变则回滚
    jedis.watch("testabcd");
    List<Object> results = tx.exec();
    long end = System.currentTimeMillis();
    System.out.println("Transaction SET: " + ((end - start)/1000.0) + " seconds");
    jedis.close();
}

// Pipelining 管道技术,可以在服务端未响应时,客户端可以继续向服务端发送请求,并最终一次性读取所有服务端的响应。
public static void jedisPipelining() {
    Jedis jedis = RedisPool.getJedis();
    Pipeline pipeline = jedis.pipelined();
    long start = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++) {
        pipeline.set("p" + i, "p" + i);
    }
    List<Object> results = pipeline.syncAndReturnAll();
    long end = System.currentTimeMillis();
    System.out.println("Pipelined SET: " + ((end - start)/1000.0) + " seconds");
    jedis.close();
}

//管道中调用事务
public static void jedisCombPipelineTrans() {
    Jedis jedis = RedisPool.getJedis();
    long start = System.currentTimeMillis();
    Pipeline pipeline = jedis.pipelined();
    pipeline.multi();
    for (int i = 0; i < 100000; i++) {
        pipeline.set("" + i, "" + i);
    }
    pipeline.exec();
    List<Object> results = pipeline.syncAndReturnAll();
    long end = System.currentTimeMillis();
    System.out.println("Pipelined transaction: " + ((end - start)/1000.0) + " seconds");
    jedis.close();
}

img

可以看到管道技术大大的提高了执行效率,但它不支持事物,把事物放到管道中执行效率介于两者之间

2.多机环境

ShardedJedis是基于一致性哈希算法实现的分布式Redis集群客户端
首先修改配置文件中的端口号,再开启一个Redis

img

新建个连接池类,和单机环境差不多,只是连接池对象不一样

//sharded jedis连接池
private static ShardedJedisPool pool;

private static Integer maxTotal = 20;
private static Integer maxIdle = 20;
private static Integer minIdle = 20;
private static Boolean testOnBorrow = true;
private static Boolean testOnReturn = true;

private static String redis1Ip = "192.168.8.10";
private static Integer redis1Port = 6379;
private static String redis2Ip = "192.168.8.10";
private static Integer redis2Port = 6380;


private static void initPool() {
    JedisPoolConfig config = new JedisPoolConfig();
    config.setMaxTotal(maxTotal);
    config.setMaxIdle(maxIdle);
    config.setMinIdle(minIdle);
    config.setTestOnBorrow(testOnBorrow);
    config.setTestOnReturn(testOnReturn);

    JedisShardInfo info1 = new JedisShardInfo(redis1Ip, redis1Port, 1000 * 2);
    JedisShardInfo info2 = new JedisShardInfo(redis2Ip, redis2Port, 1000 * 2);
    List<JedisShardInfo> jedisShardInfoList = new ArrayList<JedisShardInfo>(2);
    jedisShardInfoList.add(info1);
    jedisShardInfoList.add(info2);
    //分布式算法使用MURMUR_HASH,分布式策略使用DEFAULT_KEY_TAG_PATTERN
    pool = new ShardedJedisPool(config, jedisShardInfoList, Hashing.MURMUR_HASH, Sharded.DEFAULT_KEY_TAG_PATTERN);
}

static {
    initPool();
}

public static ShardedJedis getJedis() {
    return pool.getResource();
}

public static void returnResource(ShardedJedis jedis) {
    jedis.close();
}

public static void main(String[] args) {
    ShardedJedis jedis = getJedis();
    for (int i = 0; i < 10; i++) {
        jedis.set("key" + i, "value" + i);
    }
    returnResource(jedis);
    pool.destroy();//临时调用,销毁连接池中的所有连接
    System.out.println("program is end");
}

img

分布式中管道技术,即异步调用,分布式调用中不支持事务,因为事务是在服务器端实现,而分布式中每次访问的服务器可能不同

public static void jedisShardPipelinedPool() {
    ShardedJedis one = getJedis();
    ShardedJedisPipeline pipeline = one.pipelined();
    long start = System.currentTimeMillis();
    for (int i = 0; i < 100000; i++) {
        pipeline.set("sppn" + i, "n" + i);
    }
    List<Object> results = pipeline.syncAndReturnAll();
    long end = System.currentTimeMillis();
    one.close();
    System.out.println("Pipelined SET: " + ((end - start)/1000.0) + " seconds");
}

Demo地址