【重读iOS】数据持久化2:持久化方案介绍

什么是数据持久化

内存在断点后就会清空重置,为了保持数据在断点后保持,比如手机重启,就需要把数据存放在硬盘里,做持久化的保存。为什么不一直使用硬盘保存,因为内存会比硬盘更快速。所以在程序的声明周期里,数据加载在内存里,进行快速的计算,然后把需要持久保存的数据保存到硬盘里。

数据持久化就是怎么把数据存储到硬盘里的技术,准确的说,存储是硬件干的事,而对软件而言,关键任务是组织和识别。就是一块数据,你怎么识别为你需要的内容,比如4个字节,可以是一个int数字,也可以是4个字符。所以关键是找到一种格式把数据组织好,存入硬盘,然后按对应的方式再识别。

计算机里有很多地方都是这个逻辑,如音视频的编解码,HTTP请求的数据解析,传输或存储之前都要有一个组织和识别的过程。

方式

  1. plist文件
  2. 归档Archive
  3. 数据库

有了上面的理解,再看这些,不同方式的区别也就是组织数据的方式的区别

plist文件本质是一个xml文件,xml文件可以很好的定义层级关系,用字典和数组互相嵌套定义一个复杂的结构。

归档这个内部不知道是怎么实现的,但一般配合NSKeyedArchiver使用,几次对encodeWithCoder:initWithCoder:的使用情况来看,有几点可以推测:

  • 它使用key-value的方式组织
  • 它是一种层层嵌套的结构

然后数据库是更复杂的结构,应对大量数据的处理。上面两种方式最大问题是它们的修改都是整体修改,一张很大的plist文件里的某一个小部分的修改,也需要把整个文件读取,修改然后再整个重新写入,所以对于数据量大和修改频繁的情况,前两种不好。

plist文件和归档对比

@interface Book : NSObject<NSCoding>

@property (nonatomic) NSString *name;
@property (nonatomic) NSString *name1;
@property (nonatomic) NSString *name2;
@property (nonatomic) NSString *name3;

@end

建一个类,使用归档方式写入文件,然后使用字典模拟这个类的结构,把字典写入plist文件,对比两个文件:

  • plist文件更大,而且结构越复杂,差距越明显。从xml的结构上就可以猜到这个结果,xml携带了许多冗余的信息,比如标签要写两次。如果是数组,每个元素都加标签。
  • 下表展示了不同数量对象存入时,两种方式的文件大小
1个对象 10个 100个 1000个
归档 259 733 5477 52128
plist 374 2300 21290 211190

相比之下,归档文件要小很多,但从10-100-1000对比看,貌似还是和plist文件一样,都是线性增长。

  • 还有就是直接当纯文本打开两种文件,plist文件是可读的xml文件,而归档是乱码。

照着这个思路,只要找到一种描述对象内存的方式,就可以按这种方式组织内存,然后写入文件里,就可以设计一种新的持久化方案。最简单的,使用json描述对象,然后把json文件写入硬盘。神奇的是在这个例子里,10000个对象后,json文件比归档还小!!!

数据库

sqlite原生操作

  1. 建库

    sqlite3_open一句搞定,没有文件的会自动创建

  2. 建表

执行SQL语句create table 表名称 (列名1 列类型1, 列名2 列类型2)

列名有5种基本类型:

  • NULL: 值为一个NULL空值。
  • INTEGER: 值被标识为整数,依据值的大小可以依次被存储为1,2,3,4,6或8个字节。
  • REAL: 所有值都是浮点数值,被存储为8字节的IEEE浮点数。
  • TEXT: 值为文本字符串,使用数据库编码存储,如UTF-8、UTF-16BE或UTF-16-LE。
  • BLOB: 值是数据的二进制对象,如何输入就如何存储,不改变格式。

INTEGER 根据值的大小会自动变化,数据库中只有一个表,表中就一个列为INTEGER时,1000条数据时,值全部为1(1个字节)时数据库文件为25k,值为1LL<<60(8个字节)时为33k,可以说很明显了。

读取的时候提供了sqlite3_column_intsqlite3_column_int64两个方法来指定长度读取。

亲和类型

除了5大基本类型外,在建表的时候可以写入其他类型,会根据亲和类型,把你写入的类型转到基本类型来存储。比如常见的char(20),这个是TEXT的亲和类型,数据库内部实际按TEXT存储,但建表的时候可以char(20)这么写。

列的亲和类型

  1. 插入数据

insert into 表名称 (列名1,列名2) values (值1,值2)
然后执行sql语句就可以了。

注意:不指定列名时表示对所有列都插入数据;值是字符串类型的要使用引号包括起来;

  1. 查询数据

select * from 表名称,或者指定查询的列select 列名1,列名2 from 表名称

然后后面可以接查询条件:

where子语句
  • 比价和逻辑运算符 > = < like not between等,更多
  • 条件是可以使用括号来做组合的,如name like 'book90%' and age < 10 or age > 100name like 'book90%' and (age < 10 or age > 100)完全不同的性质
  • AND和OR连接条件
  • LIKE用来进行文本的匹配,一般使用通配符,百分号%代表0个或多个字符或数字,下划线_表示单个数字或字符
  • limit 限制查询数量 offset 指定查询的开始位置,然后limit要在前面
  • order by,用来排序结果,order by 列名1[asc][desc],列名2,列名...,asc和desc用来指定递增或递减排序。
  1. 更新数据

update Book set 列名1 = 值1, 列名2 = 值2 [条件语句]
一种方式值直接把值写入sql语句里,然后执行,还有一种是在值的位置填入问号?,然后使用sqlite3_bind系列的函数绑定数据,具体操作示例:

sqlite3_stmt *stmt;
   sqlite3_prepare_v2(dbHanle, [updateSql cStringUsingEncoding:NSUTF8StringEncoding], (int)updateSql.length, &stmt, nil);
   //1
   sqlite3_bind_text(stmt, 1, [book.name cStringUsingEncoding:NSUTF8StringEncoding], book.name.length, nil);
  sqlite3_bind_int64(stmt, 2, book.age);
   sqlite3_step(stmt);
   //2
   sqlite3_finalize(stmt);

位置1到2之间可循环操作多条数据。

  1. 删除数据

delete from 表名称 [条件语句],然后执行sql语句

  1. 事务
  • begin transaction 开启事务
  • commit 提交事务,把修改提交
  • end(transaction) 结束事务,结束会自动commit
  • rollback 回滚事务,上次commit或rollback之后的修改取消

使用事务的好处:

  • 多个操作时发生错误,整体回滚,确保数据库的完整性,不会出现未知的中间状态。
  • 大量插入数据时提高效率

事务和多线程

  1. 表信息
  • .tables 查看所有表明
  • select * from sqlite_master; 查看表的信息
  • .schema 查看建表的sql语句
  • 最有用的是:pragma table_info("Book");可以查看到每个表的列和对应的类型,这个让sqlite具有类似反射的能力,可以了解到自身的结构。
  1. 表修改
  • 修改表名:alter table Book rename to realB;
  • 添加列:alter table realB add column pic2 text;
  • 删除和修改列都没有办法,只能“改表名-新建表-搬移数据”这样迂回完成。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容