redis 数据库操作命令

redis的数据库操作命令包括select命令和move命令.

redis select命令
redis select命令的格式为select index, 其含义是为当前客户端选择使用哪一个全局数据库.redis服务器默认有16个全局数据库,当新客户端连接到redis服务器时,使用的是第一个(索引为0)全局数据库,更新数据和查询数据都是在其选择的数据库中进行.select命令可以让客户端在全局数据库中切换.telnet的模拟操作为:

telnet 10.7.7.132 6379
Trying 10.7.7.132...
Connected to 10.7.7.132.
Escape character is '^]'.
select 1
+OK

redis select命令对应的处理函数为selectCommand,其实现为(redis.c):

1427 static void selectCommand(redisClient *c) {
1428     int id = atoi(c->argv[1]);
1429    
1430     if (selectDb(c,id) == REDIS_ERR) {
1431         addReplySds(c,"-ERR invalid DB index\r\n");
1432     } else {
1433         addReply(c,shared.ok);
1434     }
1435 }

首先将数据库索引转换为整数,调用函数selectDb为该客户端选择索引指定的全局数据库,如果索引值无效,向客户端发送错误提示字符串,否则,发送操作成功字符串.函数selectDb的实现为(redis.c):

926 static int selectDb(redisClient *c, int id) {
927     if (id < 0 || id >= server.dbnum)
928         return REDIS_ERR;
929     c->dict = server.dict[id];
930     return REDIS_OK;
931 }

需要注意的是select命令是和客户端对象绑定的,它只是切换当前客户端的数据库,对于其他已经连接到redis服务器的客户端并没有影响,对于新连接到redis服务器的客户端,默认仍然选择的是第一个全局数据库.

redis move命令
redis move的格式为move key index,其含义是将当前数据库中包含指定key的节点迁移到索引指定的目标数据库.telnet的模拟操作为:

telnet 10.7.7.132 6379
Trying 10.7.7.132...
Connected to 10.7.7.132.
Escape character is '^]'.
set mykey 7
myvalue
+OK
move mykey 1
+OK
get mykey
nil

redis move命令对应的处理函数为moveCommand, 其实现为(redis.c):

1577 static void moveCommand(redisClient *c) {
1578     dictEntry *de;
1579     sds *key;
1580     robj *o;
1581     dict *src, *dst;
1582 
1583     /* Obtain source and target DB pointers */
1584     src = c->dict;
1585     if (selectDb(c,atoi(c->argv[2])) == REDIS_ERR) {
1586         addReplySds(c,sdsnew("-ERR target DB out of range\r\n"));
1587         return;
1588     }
1589     dst = c->dict;
1590     c->dict = src;
1591 
1592     /* If the user is moving using as target the same
1593      * DB as the source DB it is probably an error. */
1594     if (src == dst) {
1595         addReplySds(c,sdsnew("-ERR source DB is the same as target DB\r\n"));
1596         return;
1597     }
1598 
1599     /* Check if the element exists and get a reference */
1600     de = dictFind(c->dict,c->argv[1]);
1601     if (!de) {
1602         addReplySds(c,sdsnew("-ERR no such key\r\n"));
1603         return;
1604     }
1605 
1606     /* Try to add the element to the target DB */
1607     key = dictGetEntryKey(de);
1608     o = dictGetEntryVal(de);
1609     if (dictAdd(dst,key,o) == DICT_ERR) {
1610         addReplySds(c,sdsnew("-ERR target DB already contains the moved key\r\n"));
1611         return;
1612     }
1613 
1614     /* OK! key moved, free the entry in the source DB */
1615     dictDeleteNoFree(src,c->argv[1]);
1616     server.dirty++;
1617     addReply(c,shared.ok);
1618 }

Line1583:1590获得客户端当前连接的数据库和目标索引对应的数据库.Line1592:1597如果目标数据库和客户端当前连接数据库相同,则向客户端返回错误提示字符串.Line1599:1604检查包含指定key的哈希节点在当前数据库中是否存在,如果不存在,向客户端返回错误提示字符串.Line1606:1612将该哈希节点存储在目标数据库中,这里只是把节点的key进行哈希映射,获得在目标数据库中的BUCKET索引,然后把该节点插入到目标数据库的BUCKET索引的链表中,并不涉及到内存拷贝,全是指针操作.Line1614:1615调用函数dictDeleteNoFree在当前数据库中(节点被移除的数据库)删除该节点,该函数的实现为(dict.c):

252 int dictDeleteNoFree(dict *ht, const void *key) {
253     return dictGenericDelete(ht,key,1);
254 }

调用函数dictGenericDelete在数据库中删除该哈希节点,注意传入的第三个参数为1,即不释放该哈希节点中key和value,因该key和value仍然存储于另外一个数据库中.
回到函数moveCommand, Line1616更新数据库更新次数.最后向客户端发送操作成功提示字符串.

猜你喜欢

转载自blog.csdn.net/azurelaker/article/details/81571016