jedis指令

原理:redis

 

jedis底层主要有两个类: 
redis.clients.jedis.Protocol 
redis.clients.jedis.Connection 
Connection负责client与server之间通讯,Protocol是client与server之间通讯协议。数组

 1 public class Connection implements Closeable {  2 private static final byte[][] EMPTY_ARGS = new byte[0][];  3     private String host = "localhost"; //redis服务器地址(默认"localhost")
 4     private int port = 6379;//port:服务端号(默认6379)
 5     private Socket socket;  6     private RedisOutputStream outputStream;//redis-client发送给redis-server的内容
 7     private RedisInputStream inputStream;//redis-server返回给redis-client的内容
 8     private int pipelinedCommands = 0;//管道命令数
 9     private int connectionTimeout = 2000;//链接超时时间(默认2000ms)
 10     private int soTimeout = 2000;//响应超时时间(默认2000ms)
 11     private boolean broken = false;  12 
 13 ...  14 
 15 /**主要方法*/
 16 
 17 //链接
 18  public void connect() {  19         if(!this.isConnected()) {  20             try {  21                 this.socket = new Socket();  22                 this.socket.setReuseAddress(true);  23                 this.socket.setKeepAlive(true);  24                 this.socket.setTcpNoDelay(true);  25                 this.socket.setSoLinger(true, 0);  26                 this.socket.connect(new InetSocketAddress(this.host, this.port), this.connectionTimeout);  27                 this.socket.setSoTimeout(this.soTimeout);  28                 this.outputStream = new RedisOutputStream(this.socket.getOutputStream());  29                 this.inputStream = new RedisInputStream(this.socket.getInputStream());  30             } catch (IOException var2) {  31                 this.broken = true;  32                 throw new JedisConnectionException(var2);  33  }  34  }  35 
 36  }  37 
 38 //发送命令内容
 39 protected Connection sendCommand(Command cmd, byte[]... args) {  40         try {  41             this.connect();  42             Protocol.sendCommand(this.outputStream, cmd, args);  43             ++this.pipelinedCommands;  44             return this;  45         } catch (JedisConnectionException var6) {  46             JedisConnectionException ex = var6;  47 
 48             try {  49                 String errorMessage = Protocol.readErrorLineIfPossible(this.inputStream);  50                 if(errorMessage != null && errorMessage.length() > 0) {  51                     ex = new JedisConnectionException(errorMessage, ex.getCause());  52  }  53             } catch (Exception var5) {  54  ;  55  }  56 
 57             this.broken = true;  58             throw ex;  59  }  60  }  61 }  62 //协议
 63 public final class Protocol {  64 
 65 //命令的发送都是经过redis.clients.jedis.Protocol的sendCommand来完成的,就是对RedisOutputStream写入字节流 
 66 /**
 67 *[*号][消息元素个数]\r\n ( 消息元素个数 = 参数个数 + 1个命令)  68 *[$号][命令字节个数]\r\n  69 *[命令内容]\r\n  70 *[$号][参数字节个数]\r\n  71 *[参数内容]\r\n  72 *[$号][参数字节个数]\r\n  73 *[参数内容]\r\n  74 */
 75 private static void sendCommand(RedisOutputStream os, byte[] command, byte[]... args) {  76         try {  77             os.write((byte)42);  78             os.writeIntCrLf(args.length + 1);  79             os.write((byte)36);  80  os.writeIntCrLf(command.length);  81  os.write(command);  82  os.writeCrLf();  83             byte[][] e = args;  84             int var4 = args.length;  85 
 86             for(int var5 = 0; var5 < var4; ++var5) {  87                 byte[] arg = e[var5];  88                 os.write((byte)36);  89  os.writeIntCrLf(arg.length);  90  os.write(arg);  91  os.writeCrLf();  92  }  93 
 94         } catch (IOException var7) {  95             throw new JedisConnectionException(var7);  96  }  97  }  98 }  99 
100 //返回的数据是经过读取RedisInputStream 进行解析处理后获得的
101   /** 
102  * public static final byte PLUS_BYTE = 43; 103  * public static final byte DOLLAR_BYTE = 36; 104  * public static final byte ASTERISK_BYTE = 42; 105  * public static final byte COLON_BYTE = 58; 106 
107  * "+": 状态回复(status reply) PLUS_BYTE 108  * * <pre> 109  * 状态回复一般由那些不须要返回数据的命令返回,这种回复不能包含新行。 110  * eg: 111  * cli: set name zhangsan 112  * server: +OK 113  * </pre> 114  * 115  * "$": 批量回复(bulk reply) DOLLAR_BYTE 116  * 服务器使用批量回复来返回二进制安全的字符串,字符串的最大长度为 512 MB。 117  * eg: 118  * cli: get name 119  * server: $8\r\nzhangsan\r\n 120  * 空批量回复: 121  * 若是被请求的值不存在, 那么批量回复会将特殊值 -1 用做回复的长度值。当请求对象不存在时,客户端应该返回空对象,而不是空字符串。 122  * 123  * "*": 多条批量回复(multi bulk reply) ASTERISK_BYTE 124  * * 多条批量回复是由多个回复组成的数组, 数组中的每一个元素均可以是任意类型的回复, 包括多条批量回复自己。 125  * eg: 126  * cli: lrange mylist 0 3 127  * server: *4\r\n 128  * :1\r\n 129  * :2\r\n 130  * :3\r\n 131  * $3\r\n 132  * foo\r\n 133  * 多条批量回复也能够是空白的, 134  * eg: 135  * cli: lrange mylist 7 8 136  * server: *0\r\n 137  * 无内容的多条批量回复(null multi bulk reply)也是存在的, 好比当 BLPOP 命令的阻塞时间超过最大时限时, 它就返回一个无内容的多条批量回复, 这个回复的计数值为 -1 : 138  * eg: 139  * cli: blpop key 1 140  * server: *-1\r\n 141  * 多条批量回复中的元素能够将自身的长度设置为 -1 , 从而表示该元素不存在, 而且也不是一个空白字符串(empty string)。 142  * 143  * ":": 整数回复(integer reply) COLON_BYTE 144  * * 整数回复就是一个以 ":" 开头, CRLF 结尾的字符串表示的整数。 145  * eg: 146  * cli: exists name 147  * server: :1 148  * 149  * "-": 错误回复(error reply) MINUS_BYTE 150    */ 
151 private static Object process(RedisInputStream is) { 152         byte b = is.readByte(); 153         if(b == 43) { 154             return processStatusCodeReply(is); 155         } else if(b == 36) { 156             return processBulkReply(is); 157         } else if(b == 42) { 158             return processMultiBulkReply(is); 159         } else if(b == 58) { 160             return processInteger(is); 161         } else if(b == 45) { 162  processError(is); 163             return null; 164         } else { 165             throw new JedisConnectionException("Unknown reply: " + (char)b); 166  } 167  } 168 
169 }

以Jedis的get方法为例:缓存

 

/** * Get the value of the specified key. If the key does not exist null is returned. If the value * stored at key is not a string an error is returned because GET can only handle string values. * <p> * Time complexity: O(1) * @param key * @return Bulk reply */
  public String get(final String key) { checkIsInMultiOrPipeline(); client.sendCommand(Protocol.Command.GET, key); return client.getBulkReply(); }

1:checkIsInMultiOrPipeline(); 
进行无事务检查 Jedis不能进行有事务的操做 带事务的链接要用redis.clients.jedis.Transaction类。 
2:client.sendCommand(Protocol.Command.GET, key);
2.1:redis.clients.jedis.Connection connect()方法创建链接 
2.2:public final class Protocol sendCommand()方法向RedisOutputStream写入命令 
2.3:在命令写入成功以后,会将Connection的pipelinedCommands属性自增一,表示在管道中已经有一个命令了 
3:return this.client.getBulkReply(); 
get方法使用getBulkReply()获取返回结果,其余见上文redis.clients.jedis.Protocol process()方法安全

 

  • pipeline

redis是一个cs模式的tcp server,使用和http相似的请求响应协议。一个client能够经过一个socket链接发起多个请求命令。每一个请求命令发出后client一般会阻塞并等待redis服务处理,redis处理完后请求命令后会将结果经过响应报文返回给client。 
因此在多条命令须要处理时,使用pipeline效率会快得多。 
经过pipeline方式当有大批量的操做时候。咱们能够节省不少原来浪费在网络延迟的时间。pipeline方式将client端命令一块儿发出,redis server会处理完多条命令后,将结果一块儿打包返回client,从而节省大量的网络延迟开销。须要注意到是用 pipeline方式打包命令发送,redis必须在处理完全部命令前先缓存起全部命令的处理结果。打包的命令越多,缓存消耗内存也越多。因此并是否是打包的命令越多越好。具体多少合适须要根据具体状况测试。服务器

相关文章
相关标签/搜索