数据库?
现在重新来思考数据库的封装问题,首先就需要弄清楚FMDB数据库的原理和基本逻辑,首先弄清楚FMDB其实是一个封装的方法库,因为iOS中原生的SQLite API在使用上相当不友好,在使用时,非常不便。于是,就出现了一系列将SQLite API进行封装的库,例如FMDB、PlausibleDatabase、sqlitepersistentobjects等,FMDB是一款简洁、易用的封装库。通过FMDB来管理SQLite,需要添加libsqlite3.0.dylib这个框架。FMDB有三个主要的类1.FMDatabase – 表示一个单独的SQLite数据库。 用来执行SQLite的命令。2.FMResultSet – 表示FMDatabase执行查询后结果集 3.FMDatabaseQueue – 如果你想在多线程中执行多个查询或更新,你应该使用该类。这是线程安全的
使用数据库的第一件事,就是在特定的路径下建立一个数据库。但是要注意的是,iOS环境下只有document directory 是可以进行读写的。而Resource资料夹底下的东西都是read-only。因此,建立的数据库必须放在document 资料夹下。创建FMDatabase对象时,参数为SQLite数据库的文件路径。该路径可以是以下三种之一:1.文件路径。该文件路径无需真实存,如果不存在会自动创建。2..空字符串(@”")。表示会在临时目录创建一个空的数据库,当FMDatabase 链接关闭时,文件也被删除。3.NULL. 将创建一个内在数据库。同样的,当FMDatabase连接关闭时,数据会被销毁。
[FMDatabase databaseWithPath:]
如果是新建的数据库,一开始里面是没有类似于Excel表格的。建立Excel表格的方式很简单。但在和数据库交互时,数据库必须是打开状态。执行更新后都会返回一个BOOL值。YES表示执行成功,否则就表示出现错误 。通过调用 lastErrorMessage或lastErrorCode方法可以得到更多信息。
那么又回归到了最本质的问题,为什么总是感觉我不会使用这个FMDB第三方库来操作原生的SQLite数据呢?我是用的太少还是说有什么关键的地方没有学到,可是是哪一点没有学好呢?看来的仔细排查。首先我知道FMDB是一个对原生SQLite数据库进行操作而封装的库。那么作为一个数据库来说,肯定就是为了存储东西数据嘛!而且通常情况下存储的都是表格也就是类似于Excel的这种表格。可是如何才能把这种表格的数据进行方便的操作就是FMDB的意义所在。你可能会问,既然里面是以类似于键值对的形式存储起来,那么为什么不考虑用可变字典来存储数据呢?对呀?为什么不适用可变字典呢?问题就是字典里的键值对根本不具备数据库的“增删改查”的灵活性,而且你还会发现一个区别就是字典里的键不能相同,也就是不能够存在重复数据的情况。也就是说:一个键只能对应一个值,但是数据库就不一样了。数据库的一个键可以对应很多个值!而且最关键最关键的就是,数据里的数据是可以全工程共享的。而存在可变字典里的键值对,根本很不方便在全工程里使用!
还有对于一个表格来说首先就是要创建吧?当然工程里的表格是不能直接被创建的,因为这样就跟字典没有什么两样了!根本无法使得这个存储数据的表格在全工程里被调用了!所以必须将这个看似字典其实更类似于Excel的表格放到一个数据库里,而且必须把数据库放到一个固定的路径里。这样整个工程都可以根据这个数据库的固定路径找到数据库顺而找到这个更类似于Excel的表格。从而就能够对表格里的数据键值对进行编辑了!
好了,现在尝试一下通过FMDB如何创建数据库又如何编辑数据库里面的表格里的键值对。首先给这个类输入一个路径参数固定通过FMDB的初始化方式实例化一个的SQLite数据库对象。这里的NSHomeDirectory()就是app应用的根地址!然后必须放在根地址的可读可写的Documents文件夹里,同时设置好这个数据库的名字叫做data.db。
[[FMDatabase alloc]initWithPath:[NSString stringWithFormat:@"%@/Documents/data.db",NSHomeDirectory()]];
接着判断已经实例化的对象的打开数据库方法是否为真,如果为真,就在这个数据库里面执行对象的创建表格的方法。create创造一个表格,名字叫XXX,然后传入一个数组,像是一个字典中包含所有键的数组。
[对象 executeUpdate:@"create table 表名(键1,键2,键3)”]
现在表格已经创建完成,就可以往表格里面添加东西进行编辑了,编辑就是增删改查!首先就是往表格里面添加内容,也就是键值对的形式。使用insert插入到表格中所有键的值,更像是一个字典中的值的数组呀!
[对象 executeUpdate:@"insert into 表名 values(值1,值2,值3)”]
现在就是删除表格中满足特定条件的键值对,delete从表格中,判断的条件就是根据值来进行分类,只要一个键的值是条件里的限定值,就进行删除操作!
[对象 executeUpdate:@"delete from 表名 where 键1 = ? or 键2 = ? or 键3 = ?”,限定值,限定值,限定值]
所谓的替换依然使用where来进行条件判断,如果只要满足where里的某一类键的值的条件,就通过set来重新对这类键的值进行设置。
[对象 executeUpdate:@"update 表名 set 键 = ? where 值 > 30(范围)",替补内容]
最后就是通过FMResultSet创建一个集合来接收通过select来接收的表格里所有的键值对。但由于这个result是一个集合,所以不能使用遍历,因为集合类似于链表,头结点是空的,而且是没有顺序的。因此通过While同时结合[result next]的方法在While的循环里每次都判断[result next]的值是否为空,这样就可以实现对集合的键值对逐行进行判断。同时在while循环的遍历时,通过创建字符串对象或其它data数据来接收集合里每一行的所有键所对应的值。同时因为数据库里面的表格里只能存储string类型和data类型的键值对。所以通常接收也用相应地类型。要么NSString,要么NSData。而且这里学到一个新东西就是创建一个数据模型的新型方式,先总结一下过去创建一个有值的字典的集中方式,肯定无一例外首先都是先实例化一个对象,要么在实例化对象的时候就直接给字典里添加键值对,要么在实例化字典对象之后,在以set方式来进行添加一个键值对,或者以set的方式同时添加键数组和值数组。现在再总结一下过去只要一面临很多键值对时,如果想要提取出键值对里面键所对应的值,首先想到的方法就是建立一个数据模型,至于为什么要建立一个数据模型好型并没有描述。要知道数据库的表格里面其实的每一行都相当于三个键值对并排而存在。所以在通过while和[result next]结合使用遍历集合中的每一行时,每一次都相当于遍历一个字典里的所有键值对。话说到这儿,其实思路也很清晰了,就是其实数据库的表格更像是一个包含许多个相类似字典的数组,这才是数据库的表格的本质。那么在遍历表格里的每一行时就非常类似于遍历一个数组中的每一个字典。那么如何才能在不用数据模型的情况下接收并存储原本存储在表格的每一行的键值对呢?其实就是将原本设置在模型.h文件中的模型对象的属性现在直接在while的遍历里进行初始化的同时并将数据库的表格里的每一行的键值对的键对应的值赋值初始化的字符串对象或Data对象。然后将初始化的所有对象名组合成一个数组对象添加到可变数组中。比较model数据模型,这个while遍历里本该使用[model setValueWithDictionary:Dict]KVC方法来对数据模型model对象的所有属性进行赋值。然后是将model对象添加到可变数组中,而不使用数据模型时虽然将原本写在数据模型.h文件里的属性全部移到了while的遍历循环里,而且相当于在初始化属性的同时就将字典键对应的值赋值给属性。那么将这些在While遍历里创建的属性组合成一个数组对象然后添加到可变数组中和那种将数据模型对象添加到可变数组中,在使用时有什么不一样么?当然答案肯定是不一样的,因为可变数组中添加的是数据模型对象时想要获取值是通过点语法来实现,而当可变数组中添加的是装了属性名的数组对象时想要获取值必须通过数组加下标号来实现!不知你有没有发现,其实这就是Model数据模型诞生的本质!
1、NSHomeDirectory()就是 App Home。包含App bundle的目录,不要在该路径下写任何文件。
/Documents/。使用该路径放置关键数据,也就是不能通过App重新生成的数据。该路径可通过配置实现iTunes共享文件。可被iTunes备份。(现在保存在该路径下的文件还需要考虑iCloud同步)
/Library/。该路径下一般保存着用户配置文件。可创建子文件夹。可以用来放置您希望被备份但不希望被用户看到的数据。该路径下的文件夹,除Caches以外,都会被iTunes备份。
/tmp/。使用该路径保存临时文件。App应该删除那些不再被使用的文件,系统也会在App关闭后删除残留文件。该路径下的文件不会被iTunes备份。
5.数据源追加后重载数据显示在tableView上,只要对数据库编辑后都需要重载数据,使用完数据库需要关闭数据库,如何提高效率呢?数据库做成一个单例,在应用启动的时候,就打开数据库,当进入后台就关闭数据库。
[fm beginTransaction];
[fm rollback];//发现错误全部撤销删除
[fm commit];// 如果没有错误,则进行提交