数据存储
内存存储
常见的内存缓存框架有:
`NSCache`、`TMMemoryCache`、
`PINMemoryCache`、`YYMemoryCache`。
适合高频访问,内存占用小的 ,非持久化数据,断电后丢失。
NSCache
苹果提供的一个简单的内存缓存,它有着和 `NSDictionary` 类似的 API
它是线程安全的
YYMemoryCache
内部用`双向链表`和 `NSDictionary` 实现了 `LRU 淘汰算法`(Least recently
used,最近最少使用)
1. APP会优先请求内存缓冲中的资源
2. 如果内存缓冲中有,则直接返回资源文件, 如果没有的话,则会请求资源文
件,这时资源文件可能存储在服务端,需要进行网络请求获取,也可以是本地文
件,需要操作文件系统或数据库来获取。
3. 获取到的资源文件,先缓存到内存缓存,方便以后不再重复获取,节省时间。
4. 然后就是从缓存中取到数据然后给app使用。
内存警告
内存警告时需要释放一些占用空间大,当前不再使用的数据
磁盘
存储
持久化的文件,信息等
分为两大类:
文件系统存储和数据库系统存储
文件系统:
把数据组织成相互独立的数据文件。
整体无结构
适合文件大,特异,无关联
数据库系统:
整体数据的结构化,
管理数据库的存储,事务,以及对数据库的操作
适合小,杂,多,排序,查询等
文件系统存储
存储方案有`plist文件存储`,`NSUserDefalut存储`,`keyChain存储`,
`NSKeyedArchiver`(序列化存储),NSData
plist文件
一些hc代码,固定配置,key-value 形式存储
本质是XML文件
NSUserDefaults存储
plist文件可视化编辑,如果使用代码读取,那么使用 NSUserDefaults 存取
本质:
本质是管理plist 文件,系统提供这个管理类,方便存取
优点:
`NSUserDefaults`会将`plist`文件的数据读取到缓存中,因此访问速度会很快
注意:
1.存储系统类型,不能是自定义
2.不能是可变集合或者可变对象
KeyChain
安全:
是一个安全的存储容器,所以非常适合保存一些敏感信息到设备中
位置:
数据保持在系统中,但是又在app沙盒之外。
因此app卸载后重新安装数据还在,除非更新系统
共享:
通过`keychain access groups`可以在不同应用之间共享`keychain`中的数
据。
要求在保存数据到`keychain`的时候指定`group`。
公司其它多app账号授权互通
位置:
`KeyChain`数据保存的地方是一个`sqlite数据库`
位于`/private/var/Keychains/keychain-2.db`
用户不需要关系数据库操作
数据是加密的
NSKeyedArchiver
前面说过,NSUserDefaults 可以存储系统一些数据类型,不可变,非自定义
的。
@interface NSKeyedArchiver : NSCoder
NSKeyedArchiver 就可以存储几乎绝大部分数据类型
存
归档,或者叫 序列化
遵循协议:
自定义类需要遵循对应协议,系统不用
NSCoding: 不可变对象遵循
NSMutableCoding:可变对象code协议
调用方法:NSKeyedArchiver - encode xx
- (void)encodeObject:(nullable id)object forKey:(NSString *)key;
- (void)encodeConditionalObject:(nullable id)object forKey:(NSString
*)key;
- (void)encodeBool:(BOOL)value forKey:(NSString *)key;
【 encodeXX :
Int,Int32,Int64,Float,Double,Bytes】
取
解档,或者叫 反序列化
NSKeyedUnarchiver - decode 方法
- (nullable id)decodeObjectForKey:(NSString *)key;
- (BOOL)decodeBoolForKey:(NSString *)key;
- (int)decodeIntForKey:(NSString *)key; // may raise a
range exception
- (int32_t)decodeInt32ForKey:(NSString *)key;
- (int64_t)decodeInt64ForKey:(NSString *)key;
- (float)decodeFloatForKey:(NSString *)key;
- (double)decodeDoubleForKey:(NSString *)key;
小结:
`NSKeyedArchiver`非常适合把一个自定义的对象序列化后存储到文件系统中去
NSData
直接利用系统函数,把数据保存到指定的文件目录下。
图片,歌曲,视频一般都是通过这种形式存储的。
数据库
基本概念
库
database 用来存储容器,对外可见 .db 文件
表
Table 存放具体数据的容器,key-value形式
CREATE TABLE `CLOTHES` (
`key` int(11) NOT NULL AUTO_INCREMENT,
`value` char(255) NOT NULL DEFAULT '',
PRIMARY KEY (`k`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
id:唯一序号
通常表数据可以增删改查,排序等等
SQL
操作表格数据的语句,增删改查 命令或语句
关系型数据库
数据以二维表格形式存储,并通过对多个表格进行分类、合并、连接或选取等运
算来实现数据库的管理。
服务端:
常见有`Oracle`和`MySQL`
移动端:
最常用的SQlite
非关系型数据库
在超大规模和高并发的SNS类型的web2.0纯动态网站中有着非常好的性能
NoSQL:
(NoSQL = Not Only SQL ),意即“不仅仅是SQL”, 泛指非关系型数据库。
非关系型数据库 又分为:
键值存储数据库(key-value)(比如Redis数据库)、
列存储(Column-oriented)数据库、
面向文档(Document-Oriented)数据库、
图形数据库。
服务端特别互联网时代,对非关系行数据库有非常广泛的应用。
在移动端有代表性的:
Realm(跨平台)
ACID
是指数据库管理系统(`DBMS`)在写入或更新资料的过程中,为保证事务
(`transaction`)是正确可靠的,所必须具备的四个特性:
原子性(`atomicity`,或称不可分割性)、
一致性(`consistency`)、
隔离性(`isolation`,又称独立性)、
持久性(`durability`)。
Sqlite
特点
关系型数据库
轻型的数据库
遵守`ACID`的关系型数据库管理系统
跨平台
sql流程
一个对Employee表的数据操作流程如下:
1. SQL语句 ->
2. 触发磁盘I/O ->
3.磁盘返回一个表对应的`Index`表【索引】的一页Page,
包含若干条记录 ->
4. 在上述记录当中找到目标记录,如果没有找到
满足条件的记录,则循环第2步骤和第3步骤,
直到找到满足条件的记录->
5.根据`Index`表的记录里存放的`position`信息
找到原始表记录的位置 ->
6.对原始表当中的目标记录进行操作,完成SQL操作。
原理
Core层
1接口层
2编译器
语法分析
词法分析
代码生成
3虚拟机
Backend层
4.B-Tree (B 树)
5.Pager
6.OS 接口
database
辅助功能
Accessories
Backend层的辅助层: Accessories
包括:工具类Utils 和测试代码 Test Code
业务原理
SQLite由很多部分组成-parser,tokenize,virtual machine等等。
但是从程序员的角度,最需要知道的是:connection, statements, B-tree和
pager。
它们之间的关系如下:
三个主要方面:API,事务(Transaction)和锁(Locks)。从技术上来说,B-tree和
pager不是API的一部分
一个独立的事务(Transaction) 环境有一个连接(Connection),
一个连接对应 多个statement。
每一个statement都和一个connection关联,它通常表示一个编译过的SQL语
句,在内部,它以VDBE字节码表示。
Statement包括执行一个命令所需要一切,包括保存VDBE程序执行状态所需的资
源,指向硬盘记录的B-树游标,以及参数等等
B-tree和pager:
一个connection可以有多个database对象---一个主要的数据库以及附加的数据
库,每一个数据库对象有一个B-tree对象,一个B-tree有一个pager对象(这里的
对象不是面向对象的“对象”,只是为了说清楚问题)
Statement最终都是通过connection的B-tree和pager从数据库读或者写数据,
通过B-tree的游标(cursor)遍历存储在页面(page)中的记录。游标在访问页面之
前要把数所从disk加载到内存,而这就是pager的任务。任何时候,如果B-tree
需要页面,它都会请求pager从disk读取数据,然后把页面(page)加载到页面缓
冲区(page cache),之后,B-tree和与之关联的游标就可以访问位于page中的记
录了。
如果cursor改变了page,为了防止事务回滚,pager必须采取特殊的方式保存原
来的page。总的来说,pager负责读写数据库,管理内存缓存和页面(page),
以及管理事务,锁和崩溃恢复(这些在事务一节会详细介绍).
执行流程
1. 连接数据库(Connect to the database)
2.执行事务(Perform transactions)
3.断开连接(Disconnect from the database)
代码片段:
//打开数据
rc = sqlite3_open("foods.db", &db);
//关闭数据库
sqlite3_close(db);
磁盘I/O瓶颈
一次查询往往无法通过一次I/O 操作完成。所以如何减少磁盘I/O 的次数成为我
们优化`SQlite`性能的关键
内存页
内存和磁盘中的数据存储和交互都是以页(page)为单位的。即使内存只需要1
个字节的数据,从磁盘读取的时候也是拿到一个或多个`Page`,这是系统级别的
一种预先缓存策略
索引表
内存按页分段数据,一页能包含数据条数有限,因此,大量查询 结果的数据关系
就用到索引了
映射原表来记录key索引字段表 :索引表
B树
二叉树的高度会过大,而矮胖树结构便于 磁盘IO,尽量减小原始表的大小,避免
因树过于庞大