转:https://www.cnblogs.com/beiluowuzheng/p/9738159.html

服务器中的数据库

Redis服务器将所有数据库都保存在服务器状态redis.h/redisServer结构体的db数组中,db数组的每个项都是一个redis.h/redisDb结构体,每个redisDb结构体代表一个数据库

redis.h

?
1
2
3
4
5
6
struct redisServer {
    ……
    //一个数组,保存着服务器中所有数据库
    redisDb *db;
    ……
};

  

在初始化服务器时,程序会根据服务器状态的dbnum属性来决定应该创建多少个数据库:

redis.h

?
1
2
3
4
5
6
struct redisServer {
    ……
    //服务器的数据库数量
    int dbnum;                    
    ……
};

  

dbnum属性由服务器配置的database选项决定,默认情况下,该选项的值为16,所以Redis服务器默认会创建16个数据库,如图1-1所示

图1-1   服务器数据库示例

切换数据库

每个Redis客户端都有自己的目标数据库,每当客户端执行数据库写命令或者数据库读命令的时候,目标数据库就会成为这些命令的操作对象。默认情况下,Redis客户端的目标数据库为0号数据库,但客户端可以通过执行SELECT命令来切换目标数据库。以下代码示例演示了客户端在0号数据库设置并读取键msg,之后切换到2号数据库并执行类似操作的过程:

?
1
2
3
4
5
6
7
8
9
10
11
12
127.0.0.1:6379> SET msg "hello world"
OK
127.0.0.1:6379> GET msg
"hello world"
127.0.0.1:6379> SELECT 2
OK
127.0.0.1:6379[2]> GET msg
(nil)
127.0.0.1:6379[2]> SET msg "another world"
OK
127.0.0.1:6379[2]> GET msg
"another world"

  

在服务器内部,客户端状态redisClient结构的db属性记录了客户端当前的目标数据库,这个属性是一个指向redisDb结构的指针:

redis.h

?
1
2
3
4
5
6
typedef struct redisClient {
    ……
    //记录客户端当前正在使用的数据库
    redisDb *db;
    ……
} redisClient;

  

redisClient.db指针指向redisServer.db数组的其中一个元素,而被指向的元素就是客户端你的目标数据库。如果某个客户端的目标数据库为1号数据库,那么这个客户端所对应的客户端状态和服务器状态之间的关系如图1-2所示

图1-2   客户端的目标数据库为1号数据库

如果这时客户端执行命令SELECT 2,将目标数据库改为2号数据库,那么客户端的状态和服务器之间的关系将更新到如图1-3

图1-3   客户端的目标数据库为2号数据库

通过修改redisClient.db指针,让它指向服务器中的不同数据库,从而实现切换目标数据库的功能,这就是SELECT命令的实现原理

数据库键空间

Redis是一个键值对数据库服务器,服务器中的每个数据库都由redis.h/redisDb结构体表示,其中,redisDb结构体的dict字典保存了数据库中的所有键值对,我们将这个字典称为键空间

redis.h

?
1
2
3
4
5
typedef struct redisDb {
    //数据库键空间,保存着数据库中所有键值对
    dict *dict;               
    ……
} redisDb;

  

键空间和用户所见的数据库是直接对应的:

  • 键空间的键也就是数据库的键,每个键都是一个字符串对象
  • 键空间的值也就是数据库的值,每个值可以是字符串对象、列表对象、哈希表对象、集合对象和有序集合对象中任意一种Redis对象、集合对象和有序集合对象中的任意一种Redis对象

举个栗子,如果我们在空白的数据库中执行以下命令:

?
1
2
3
4
5
6
7
8
9
10
127.0.0.1:6379> SET message "hello world"
OK
127.0.0.1:6379> RPUSH alphabet "a" "b" "c"
(integer) 3
127.0.0.1:6379> HSET book name "Redis in Action"
(integer) 1
127.0.0.1:6379> HSET book author "Josiah L. Carlson"
(integer) 1
127.0.0.1:6379> HSET book publisher "Manning"
(integer) 1

  

那么在这些命令之后,数据库键空间将会是图1-4所展示的样子:

  • alphabet是一个列表键,键的名字是一个包含字符串"alphabet"的字符串对象,键的值则是一个包含三个元素的列表对象
  • book是一个哈希表键,键的名字是一个包含字符串"book"的字符串对象,键的值则是一个包含三个键值对的哈希表对象
  • message是一个字符串键,键的名字是一个包含字符串"message"的字符串对象,键的值则是一个包含字符串"hello world"的字符串对象

图1-4   数据库键空间例子

因为数据库的键空间是一个字典,所以所有针对数据库的操作,比如添加一个键值对到数据库,或者从数据库中删除一个键值对,又或者在数据库中获取某个键值对等,实际上都是通过对键空间字典进行操作来实现,以下几个小节将分别介绍数据库的增删改查操作的实现原理

添加新键

添加一个新的键值对到数据库,实际上就是将一个新的键值对添加到键空间字典中,其中键为字符串对象,而值可以是任意一种类型的Redis对象。举个栗子,如果键空间当前的状态如图1-4所示,那么在执行以下命令后:

?
1
2
127.0.0.1:6379> SET date "2013.12.1"
OK

  

键空间将添加一个新的键值对,这个新键值对的键是一个包含字符串"date"的字符串对象,而值对象则是一个包含字符串"2013.12.1"的字符串对象,如图1-5所示

图1-5   添加date键之后的键空间

删除键

删除数据库中的一个键,实际上就是在键空间删除一个键值对对象。举个栗子,如果键空间当前的状态如1-4所示,那么执行以下命令后:

?
1
2
127.0.0.1:6379> DEL book
(integer) 1

  

键book以及它的值将从键空间中被删除,如图1-6所示

图1-6   删除book键之后的键空间

更新键

对一个数据库键进行更新,实际上就是对键空间里面键所对应的值对象进行更新,根据值对象的类型不同,更新的具体方法也会有所不同。举个例子,如果键空间当前状态如图1-4所示,那么在执行以下命令后:

?
1
2
127.0.0.1:6379> SET message "blah blah"
OK

  

键message的值对象将从之前包含"hello world"字符串更新为"blah blah"字符串,如图1-7所示

图1-7   使用SET命令更新message键

再举个例子,如果我们继续执行以下命令:

?
1
2
127.0.0.1:6379> HSET book page 320
(integer) 1

  

那么键空间中book键的值对象(一个哈希键)将被更新,新的键值对page和320会被添加到值对象中,如图1-8所示

图1-8   使用HSET更新book

对键取值

对一个数据库键进行取值,实际上就是在键空间中取出键所对应的值对象,根据值对象的类型不同,具体的取值方法也会有所不同。举个栗子,如果键空间当前的状态如图1-4所示,那么当执行以下命令时:

?
1
2
127.0.0.1:6379> GET message
"hello world"

  

GET命令将首先在键空间中查找键message,找到键之后接着取得该键所对应的字符串对象值,之后再返回值对象所包含的字符串"hello world",取值过程如图1-9所示

图1-9   使用GET命令取值的过程

再举个例子,当执行以下命令时:

?
1
2
3
4
127.0.0.1:6379> LRANGE alphabet 0 -1
1) "a"
2) "b"
3) "c"

  

LRANGE命令将首先在键空间查找键alphabet,找到键之后接着取得该键所对应的列表对象值,之后再返回列表对象中包含的三个字符串对象的值,取值过程如图1-10所示

图1-10   使用LRANGE命令取值的过程

其他键空间操作

除了上面列出的添加、删除、更新、取值操作外,还有很多针对数据库本身的Redis命令,也是通过对键空间进行处理来完成的。比如说,用于清空整个数据库的FLUSHDB命令,就是通过删除键空间中的所有键值对来实现的。又比如说,用于随机返回数据库中某个键的RANDOMKEY命令,就是通过在键空间中随机返回一个键来实现的。另外,用于返回数据库键数量的DBSIZE命令,就是通过返回键空间中包含的键值对的数量来实现的。类似还有EXISTS、RENAME、KEYS等,这些命令都是通过对键空间进行操作来实现的

读写键空间的维护操作

当使用Redis命令对数据库进行读写时,服务器不仅会对键空间执行指定的读写操作,还会执行一些额外的维护操作,其中包括:

  • 在读取一个键之后(读操作和写操作都要对键进行读取),服务器会根据键是否存在来更新服务器的键空间命中次数或键空间不命中次数,这两个值可以在INFO stats命令的keyspace_hits属性和keyspace_misses属性中查看
  • 在读取一个键之后,服务器会更新键的LRU(最后一次使用)时间,这个值可以用于计算键的闲置时间,使用OBJECT idletime<key>命令可以查看键key的闲置时间
  • 如果服务器在读取一个键时发现该键已过期,那么服务器会先删除这个过期键,然后才执行余下的其他操作
  • 如果客户端使用WATCH命令监视某个键,那么服务器在对被监视的键进行修改之后,会将这个键标记为脏,从而让事物程序注意到这个键已经被修改了
  • 服务器每次修改一个键之后,都会对脏键计数器的值加1,这个计数器会触发服务器的持久化以及复制操作
  • 如果服务器开启了数据库通知功能,那么在对键进行修改之后,服务器将按配置发送相应的数据库通知

转载于:https://www.cnblogs.com/kenD/p/11220569.html

redis实现数据库(一)相关推荐

  1. Redis 缓存数据库

    Redis 缓存数据库 第1章 Redis简介: redis是使用C语言编写的开源的,支持网络,基于内存,可持久性的键值对存储数据库,2013年5月之前,Redis是最流行的键值对存储数据库 Redi ...

  2. Redis缓存数据库服务器

    Redis缓存数据库服务器 Redis是一个开源的科技与内存也可持久化的日志型.Key-Value数据库 Redis的存储分为内存存储.磁盘存储和Log文件三部分,配置文件中有三个参数对其进行配置. ...

  3. Redis和数据库 数据同步问题

    Redis和数据库同步问题 缓存充当数据库 比如说Session这种访问非常频繁的数据,就适合采用这种方案:当然了,既然没有涉及到数据库,那么也就不会存在一致性问题: 缓存充当数据库热点缓存 读操作 ...

  4. redis 和 数据库mysql之间的关系

    https://www.zhihu.com/question/20734566 https://www.zhihu.com/question/19660689 http://blog.csdn.net ...

  5. redis和mysql数据不一致_高并发下为什么 redis 和数据库不一致?怎么解决?

    现在的web架构一般都用redis作为缓存层来减轻数据库的压力,数据在此架构下的读取问题,一般都是先判断redis缓存是否有数据,如果有,直接返回,否则读取数据库的数据,写入redis,返回数据,这是 ...

  6. Redis和数据库的结合

    使用 Redis 可以优化性能,但是存在 Redis 的数据和数据库同步的问题,这是我们需要关注的问题.假设两个业务逻辑都是在操作数据库的同一条记录,而 Redis 和数据库不一致. Redis 和数 ...

  7. Redis与数据库同步问题

    缓存数据与持久化数据的一致性,这个问题总结了一下(看到了一个不错的博文),其实就是读和写,还有就是要注意谁先谁后的问题. Redis 是一个高性能的key-value数据库. redis的出现,很大程 ...

  8. Redis与数据库缓存一致性问题

    一.Redis 数据一致性问题产生的原因 对 Redis和数据库的操作有 2 种方案: 1.先操作(删除) Redis,再操作数据库 2.先操作数据库,再操作(删除) Redis 上述二种方案,都希望 ...

  9. redis的数据库通知(notify-keyspace-events)

    redis的数据库通知(notify-keyspace-events) 共分为两类:一类是键空间通知 另一类是键事件通知 概述 数据库通知是redis在2.8之后新增的功能,让客户端可以已发布/订阅模 ...

  10. 项目优化:当使用redis减少数据库压力时,遇到redis写入失败,造成读取数据问题的解决方案

    场景: 我们项目用到了mq,有一个专门的服务在跑异步任务去发mq,这个mq的数据不是从数据库里面查的,而是从redis里面取的,之所以这么做,有两个原因: 1.使用redis减少数据库的压力: 2.本 ...

最新文章

  1. Girton College Info Session Abstract
  2. IDEA在debug环境下,端口被占用
  3. oa项目经验描述_OA系统为企业带来多少实用价值?移动OA又为企业解决哪些问题?...
  4. 牛客IOI周赛19-普及组 B.小y的序列
  5. 外部中断---STM32F1
  6. Android相关sdk使用
  7. 写SQL语句需要注意的点
  8. 面向生产环境!深度学习模型部署资源全辑
  9. 实现API接口调用--来源阿里云大学-归档
  10. 2015/8/7 卖出中国软件,卖早了;5只不同形态的三角形震荡股票
  11. HDU1829 A Bug's Life 并查集
  12. windows单实例的办法
  13. mysql的读写分离工具_mysql 读写分离工具
  14. 小程序源码:全新外卖侠cps5.6全套微信小程序源码下载-多玩法安装简单
  15. 理论 - 平面倒F天线(PIFA)
  16. 通信原理 | 信道特性及其数学模型
  17. java 阿里云消息推送到手机
  18. html注册新浪邮箱代码,新浪博客美化代码:邮箱快速登录
  19. Servlet思维导图总结
  20. Microsoft MSN Messenger 7.0.0205 Beta Leaked

热门文章

  1. 阿里云ECS上LVM磁盘配置
  2. Python基础——细琐知识点
  3. NodeJs回调操作Promise化
  4. mysql单列去重复group by分组取每组前几条记录加order by排序
  5. 进度条的另外一种用法
  6. python分析nginx日志
  7. 第三方控件radupload 使用方式以及报错处理
  8. 30.275MHz 调频无线对讲机原理、制作与调试
  9. Android apk签名方法
  10. android.provider.documentscontract cannot be resolved.