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必須在處理完全部命令前先緩存起全部命令的處理結果。打包的命令越多,緩存消耗內存也越多。因此並是否是打包的命令越多越好。具體多少合適須要根據具體狀況測試。服務器

相關文章
相關標籤/搜索