baiyanredis
命令含義:將 key更名爲newkey
命令格式:數據庫
RENAME key newkey
命令實戰:函數
127.0.0.1:6379> keys * 1) "kkk" 2) "key1" 127.0.0.1:6379> rename kkk key1 OK 127.0.0.1:6379> keys * 1) "key1" 127.0.0.1:6379> rename kkk kkk (error) ERR no such key
返回值: 更名成功時提示 OK ,失敗時候返回一個錯誤源碼分析
rename命令的處理函數是renameCommand():spa
void renameCommand(client *c) { renameGenericCommand(c,0); }
renameCommand()函數調用了底層通用重命名函數:code
void renameGenericCommand(client *c, int nx) { robj *o; long long expire; int samekey = 0; // 重命名以前和以後的鍵名相同,置samekey標誌爲1,不作處理 if (sdscmp(c->argv[1]->ptr,c->argv[2]->ptr) == 0) samekey = 1; // 若是重命名以前的鍵不存在,直接返回 if ((o = lookupKeyWriteOrReply(c,c->argv[1],shared.nokeyerr)) == NULL) return; // 若是置了samekey標誌爲1,表明重命名先後的鍵名相同,那麼什麼都不作,直接返回OK if (samekey) { addReply(c,nx ? shared.czero : shared.ok); return; } incrRefCount(o); // 因爲查找到了o,引用計數++ expire = getExpire(c->db,c->argv[1]); // 獲取重命名以前鍵的過時時間 if (lookupKeyWrite(c->db,c->argv[2]) != NULL) { // 若是重命名以後的鍵已經存在 if (nx) { // 是不是執行的renamenx命令 decrRefCount(o); addReply(c,shared.czero); return; } /* 重命名以後的鍵已經存在,須要刪除這個已存在的鍵 */ dbDelete(c->db,c->argv[2]); } dbAdd(c->db,c->argv[2],o); // 到這裏重命名以後的鍵必定不存在了,能夠添加這個鍵 if (expire != -1) setExpire(c,c->db,c->argv[2],expire); // 若是以前設置了過時時間,一樣給新鍵設置過時時間 dbDelete(c->db,c->argv[1]); // 新鍵建立完畢,需刪除以前的鍵 signalModifiedKey(c->db,c->argv[1]); // 發出修改鍵信號 signalModifiedKey(c->db,c->argv[2]); // 發出修改鍵信號 notifyKeyspaceEvent(NOTIFY_GENERIC,"rename_from", c->argv[1],c->db->id); // 鍵空間事件觸發 notifyKeyspaceEvent(NOTIFY_GENERIC,"rename_to", c->argv[2],c->db->id); // 鍵空間事件觸發 server.dirty++; addReply(c,nx ? shared.cone : shared.ok); }
咱們首先整理一下這個命令的思路,若是讓咱們本身去實現重命名一個鍵這個命令,應該怎麼作呢?
首先咱們會判斷一些邊界條件。咱們知道,鍵是放在鍵空間字典裏的。假設咱們如今有key1-value1和key2-value2。如今須要把key1重命名爲key2,即重命名以後生成值爲key2-value1的鍵值對。考慮如下邊界狀況:server
對於第一種狀況,若是重命名以前的鍵不存在,很簡單,這種操做是不可以執行的。直接和客戶端報告錯誤便可。
對於第二種狀況,若是重命名以後的鍵已經存在了,redis選擇先查找出value1,而後刪掉key2-value2鍵值對。目前的變量狀態僅僅有一個value1,和一個咱們輸入的key2。接下來,咱們直接往數據庫中添加key2-value1便可。最後刪掉老的key1-value1鍵值對便可。
對於第三種狀況,不做任何處理便可。進程
因爲redis會在上面的第二種狀況,即重命名以後的鍵存在的狀況下,選擇前後將key2-value二、key1-value1刪除。因此,當碰到要刪除的key-value對數據量很是大的時候,每每會形成單進程的redis的阻塞狀態,形成對外服務的不可用。因此,每每在平常開發中,這個命令會被禁止使用,和以前講過的keys命令有殊途同歸之妙。在使用過程當中咱們須要格外注意。事件