redis(3)-jedis&pipline&multi

pipline
Redis客户端执行一条命令分为如下四个过程:
1) 发送命令
2) 命令排队
3) 命令执行
4) 返回结果
其中1) +4) 称为Round Trip Time(RTT, 往返时间)。Redis提供了批量操作命令(例如mget、 mset等) , 有效地节约RTT。 但大部分命令是不支持批量操作的, 例如要执行n次hgetall命令, 并没有mhgetall命令存在, 需要消耗n次RTT。
Pipeline(流水线) 机制能改善上面这类问题, 它能将一组Redis命令进行组装, 通过一次RTT传输给Redis, 再将这组Redis命令的执行结果按顺序返回给客户端。

可以使用Pipeline模拟出批量操作的效果, 但是在使用时要注意它与原生批量命令的区别, 具体包含以下几点:
·原生批量命令是原子的, Pipeline是非原子的。
·原生批量命令是一个命令对应多个key, Pipeline支持多个命令。
·原生批量命令是Redis服务端支持实现的, 而Pipeline需要服务端和客户端的共同实现。

Pipeline虽然好用, 但是每次Pipeline组装的命令个数不能没有节制, 否则一次组装Pipeline数据量过大, 一方面会增加客户端的等待时间, 另一方面会造成一定的网络阻塞, 可以将一次包含大量命令的Pipeline拆分成多次较小的Pipeline来完成。

Redis事务
Redis提供了简单的事务功能, 将一组需要一起执行的命令放到multi和exec两个命令之间。 multi命令代表事务开始, exec命令代表事务结束, 它们之间的命令是原子顺序执行的。当开启事务之后,
后面的命令都不是立即执行的,而是QUEUED代表命令并没有真正执行, 而是暂时保存在Redis中。只有当exec执行后,才算是完成任务。如果要停止事务的执行, 可以使用discard命令代替exec命令即可。如果事务中的命令出现错误, Redis的处理机制也不尽相同。
1.命令错误
例如错将set写成了sett, 属于语法错误, 会造成整个事务无法执行。当执行exec时回滚整个事务。
2.运行时错误
例如把sadd命令写成了zadd命令, 这种就是运行时命令, 因为语法是正确的可以看到Redis并不支持回滚功能之前的命令已经执行成功, 开发人员需要自己修复这类问题。

pipline不保证事务的原子性,即pipline中的命令之间可能穿插别的命令,而redis事务则保证了事务当中的命令不会穿插别的命令。pipline只是可以减少rtt(往返时间)。redis事务也不会回滚。当你的java代码抛出异常时,你就需要手动回滚那些redis的操作。

想象一下这个场景,你的redis操作依赖于redis中的值。当你获取依赖的值得时候,很有可能这个值已经过期了。所以出现了watch命令。watch命令搭配multi使用。首先watch一个或多个key,之后开启multi,当执行exec时如果watch的值发生了不是本事务做出的改变,则回滚本事务

redis客户端jedis

1.Jedis的直连方式

Jedis(final String host, final int port, final int connectionTimeout, final int soTimeout)
·host: Redis实例的所在机器的IP。
·port: Redis实例的端口。
·connectionTimeout: 客户端连接超时。
·soTimeout: 客户端读写超时。

当连接完成时则关闭jedis。所谓直连是指Jedis每次都会新建TCP连接, 使用后再断开连接, 对于频繁访问Redis的场景显然不是高效的使用方式。

2.Jedis连接池

// common-pool连接池配置, 这里使用默认配置。
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
// 初始化Jedis连接池
JedisPool jedisPool = new JedisPool(poolConfig, "127.0.0.1", 6379);

Jedis jedis = null;
try {
	// 1. 从连接池获取jedis对象
	jedis = jedisPool.getResource();
	// 2. 执行操作
	jedis.get("hello");
} catch (Exception e) {
	logger.error(e.getMessage(),e);
} finally {
	if (jedis != null) {
    	// 如果使用JedisPool, close操作不是关闭连接, 代表归还连接池
    	jedis.close();
	}
}

同样的 用完之后需要关闭,注意这个关闭操作是吧连接归还给池而不是关闭连接。

生产环境中一般使用连接池的方式对Jedis连接进行管理, 所有Jedis对象预先放在池子中, 每次要连接Redis, 只需要在池子中借, 用完了在归还给池子。
客户端连接Redis使用的是TCP协议, 直连的方式每次需要建立TCP连接, 而连接池的方式是可以预先初始化好Jedis连接, 所以每次只需要从Jedis连接池借用即可, 而借用和归还操作是在本地进行的, 只有少量的并发同步开销, 远远小于新建TCP连接的开销。 另外直连的方式无法限制Jedis
对象的个数, 在极端情况下可能会造成连接泄露, 而连接池的形式可以有效的保护和控制资源的使用。 但是直连的方式也并不是一无是处。
Redis中Pipeline的使用方法
Jedis支持Pipeline特性, 我们知道Redis提供了mget、 mset方法, 但是并没有提供mdel方法, 如果想实现这个功能, 可以借助Pipeline来模拟批量删除, 虽然不会像mget和mset那样是一个原子命令, 但是在绝大数场景下可以使用。 下面代码是mdel删除的实现过程。

    public void mdel(List<String> keys) {
	    Jedis jedis = new Jedis("127.0.0.1");
	    // 1)生成pipeline对象
	    Pipeline pipeline = jedis.pipelined();
	    // 2)pipeline执行命令, 注意此时命令并未真正执行
	    for (String key : keys) {
	    pipeline.del(key);
	    }
	    // 3)执行命令
	    List<Object> resultList = pipeline.syncAndReturnAll();
	    for (Object object : resultList) {
	    	System.out.println(object);
	    }
    }

注意这里没有try catch finally没有关闭连接。

可以看到真正发送命令给redis的是pipline.syncAndReturnAll同时这里也会阻塞等待网络返回。遍历结果即可得到返回值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值