首页 > 代码库 > 数据持久化-CoreData、SQLite、FMDB

数据持久化-CoreData、SQLite、FMDB

1.CoreData


1.1 CoreData概述


1)Core data 是数据持久存储的最佳方式

2)Core Data 基于model-view-controller(mvc)模式下,为创建分解的cocoa应用程序提供了一个灵活和强大的数据模型框架。


3)Core Data可以是你以图形界面的方式快速的定义app的数据模型,同时在你的代码中容易获取到它。 Core Data提供了基础结构去处理常用的功能,例如:保存,恢复,撤销和重做,允许你在app中继续创建新的任务。在使用 Core Data的时候,你不用安装额外的数据库系统,因为 Core Data使用内置的SQLite数据库。(里面自动生成三个字段)


4)Core Data提供了一个通用的数据管理解决方案来处理那些所有需要数据模型的app,app使用 Core Data来管理数据对象时很多的益处


5)苹果的图形用户界面编译器-interface builder(IB),提供了对core data controller对象的预构建,从而来减少app的用户界面和它的数据模型之间的粘滞代码。在使用core data的时候你不需要考虑sql的语法问题,也不需要管理相关的逻辑树去追踪用户的行为,更不用建立新的永久机制。当你写你app的用户界面到它的core data模型的时候,它已经为你把所有的东西都做好了。


6)core data将你app的模型层放入到一组定义在内存中的数据对象。core data会追踪这些对象的改变,同时可以根据需要做相反的改变,例如用户执行撤销命令。当core data在对你app数据的改变进行保存的时候,core data会把这些数据归档,并永久性保存。它保存的数据在一些常规的文件,你可以在Finder中可以进行管理,用spotlight进行搜索,备份到cd,和email给朋友或者家人


7)在使用core data框架的时候,你可以创建一个管理对象的模型,该模型提供了对模型对象的抽象定义,这也就是我们所知道的entities,它可以在我们的程序中使用。


8)core data是一个实体-关系模型,该模型是使用Xcode的数据模型设计工具来定义的,对数据实体以及他们的关系提供了丰富的环境。

1.2 CoreData的构成及特点


1.2.1 数据最终的存储类型


SQLite数据库,XML,二进制,内存里,或自定义数据类型(Mac OS X 10.5Leopard及以后的版本中,开发者也可以通过继承NSPersistentStore类以创建自定义的存储格式)


1.2.2 好处


能够合理管理内存,避免使用sql的麻烦,高效


1.2.3 构成

1)NSManagedObjectContext(被管理的数据上下文)

操作实际内容(操作持久层)

作用:插入数据,查询数据,删除数据


2)NSManagedObjectModel(被管理的数据模型)

数据库所有表格或数据结构,包含各实体的定义信息

作用:添加实体的属性,建立属性之间的关系

操作方法:视图编辑器,或代码


3)NSPersistentStoreCoordinator(持久化存储助理)

相当于数据库的连接器

作用:设置数据存储的名字,位置,存储方式,和存储时机


4)NSManagedObject(被管理的数据记录)

相当于数据库中的表格记录


5)NSFetchRequest(获取数据的请求)

相当于查询语句


6)NSEntityDescription(实体结构)

相当于表格结构


7)后缀为.xcdatamodeld的包

里面是.xcdatamodel文件,用数据模型编辑器编辑

编译后为.momd或.mom文件


1.2.4 依赖关系


pastedGraphic.pdf


      1.3 基于SQLite数据库时,Core Data的简单使用


和SQLite的区别:只能取出整个实体记录,然后分解,之后才能得到实体的某个属性


1.3.1 构建流程


包括:创建数据上下文,创建数据模型,创建数据持久化存储助理

(1)若是新建的工程,选择空白应用程序,next

pastedGraphic_1.pdf


此时生成的工程文件AppDelegate中,会自动生成被管理的数据上下文等相关代码


(2)比如AppDelegate.h文件中,自动生成


@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;

@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;

@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;


- (void)saveContext;

  • (NSURL *)applicationDocumentsDirectory;


方法saveContext表示:保存数据到持久层(数据库)

方法applicationDocumentsDirectory表示:应用程序沙箱下的Documents目录路径

(例如/var/mobile/Applications/5FG80A45-DFB5-4087-A1B1-41342A977E21/Documents/)


(3)比如AppDelegate.h文件中,自动生成


@synthesize managedObjectContext = __managedObjectContext;

@synthesize managedObjectModel = __managedObjectModel;

@synthesize persistentStoreCoordinator = __persistentStoreCoordinator;


保存数据到持久层

- (void)applicationWillTerminate:(UIApplication *)application

{

    [self saveContext];

}

pastedGraphic_2.pdf

- (void)saveContext

{

    NSError *error = nil;

    NSManagedObjectContext *managedObjectContext = self.managedObjectContext;

    if (managedObjectContext != nil) {

        if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {

            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);

            abort();

        } 

    }

}

pastedGraphic_3.pdf

Documents目录路径

- (NSURL *)applicationDocumentsDirectory

{

    return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];

}

被管理的数据上下文

初始化的后,必须设置持久化存储助理

pastedGraphic_4.pdf

- (NSManagedObjectContext *)managedObjectContext

{

    if (__managedObjectContext != nil) {

        return __managedObjectContext;

    }

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];

    if (coordinator != nil) {

        __managedObjectContext = [[NSManagedObjectContext alloc] init];

        [__managedObjectContext setPersistentStoreCoordinator:coordinator];

    }

    return __managedObjectContext;

}

pastedGraphic_5.pdf

被管理的数据模型

初始化必须依赖.momd文件路径,而.momd文件由.xcdatamodeld文件编译而来


- (NSManagedObjectModel *)managedObjectModel

{

    if (__managedObjectModel != nil) {

        return __managedObjectModel;

    }

    NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"TestApp" withExtension:@"momd"];

    __managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];

    return __managedObjectModel;

}


持久化存储助理

初始化必须依赖NSManagedObjectModel,之后要指定持久化存储的数据类型,默认的是NSSQLiteStoreType,即SQLite数据库;并指定存储路径为Documents目录下,以及数据库名称


- (NSPersistentStoreCoordinator *)persistentStoreCoordinator

{

    if (__persistentStoreCoordinator != nil) {

        return __persistentStoreCoordinator;

    }

    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"TestApp.SQLite"];

    NSError *error = nil;

    __persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];

    if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {

        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);

        abort();

    }    

    return __persistentStoreCoordinator;

}


如果不是新工程,也可以自己写入相关代码

(4)此外还生成了TestApp.xcdatamodeld文件

(5)还自动链接了CoreData.framework

(6)在预编译头.pch文件中,加入导入了CoreData.h头文件

#import

 

1.3.2 创建数据模型(数据模型编辑器操作)


(1)创建实体(数据库表)和实体间的关系


选中.xcodedatamodel对象

在左下脚点击Add Entity添加实体

选中新添加的属性,对属性进行命名,并设置属性的数据类型Attribute Type

选中一个实体,在底部工具栏点击Add Relationship添加关系




pastedGraphic_6.pdf


(2)自动生成模型类


pastedGraphic_7.pdf

选择你要创建的数据对象

pastedGraphic_8.pdf

1.3.3 数据模版


为每个实体生成一个NSManagedObject子类

上面设置数据和获取数据时,使用的是Key-Value方式,更好的方法是通过生成强类型的NSManagedObject的子类,通过类的成员属性来访问和获取数据

(1)在数据编辑器视图中选中实体对象,

选则file菜单,点击new,点击file...,选择Core Data项,选择NSManagedObject subclass,生成该实体同名的类,

继承于NSManagedObject

  • 生成对应的.h文件


pastedGraphic_9.pdf





  • 生成对应的l.m文件

pastedGraphic_10.pdf

其中,@dynamic告诉编译器不做处理,使编译通过,其getter和setter方法会在运行时动态创建,由Core Data框架为此类属性生成存取方法


1.3.4 插入数据

在AppDelegate.m的application:didFinishLaunchingWithOptions:方法里,调用自定义方法

insertCoreData插入数据,代码如下:


- (void)insertCoreData

{

    NSManagedObjectContext *context = [self managedObjectContext];

    

    NSManagedObject *contactInfo = [NSEntityDescription insertNewObjectForEntityForName:@"School"inManagedObjectContext:context];

    [contactInfo setValue:@"name B" forKey:@"name"];

    [contactInfo setValue:@"classID 1" forKey:@"classID"];

    [contactInfo setValue:@"persons 20" forKey:@"pensons"];

    

    NSManagedObject *contactDetailInfo = [NSEntityDescription insertNewObjectForEntityForName:@"ContactDetailInfo"inManagedObjectContext:context];

    [contactDetailInfo setValue:@"age 22" forKey:@"age"];

    [contactDetailInfo setValue:@"name B" forKey:@"name"];

    [contactDetailInfo setValue:@"classID 1" forKey:@"classID"];

    

    [contactDetailInfo setValue:contactInfo forKey:@"name"];

    [contactInfo setValue:contactDetailInfo forKey:@"classID"];

    

    NSError *error;

    if(![context save:&error])

    {

        NSLog(@"不能保存:%@",[error localizedDescription]);

    }

}


创建数据上下文,调用insertNewObjectForName方法,创建两个数据记录NSManagedObject,然后就可以对之前数据模型编辑视图中定义的属性进行赋值。此时的数据只在内存中被修改,最后调用数据上下文的save方法,保存到持久层


1.3.5 查询数据


在调用了insertCoreData之后,可以调用自定的查询方法dataFetchRequest来查询插入的数据


- (void)dataFetchRequest

{

    NSManagedObjectContext *context = [self managedObjectContext];

    NSFetchRequest *fetchRequest = [[[NSFetchRequest alloc] init] autorelease];

    NSEntityDescription *entity = [NSEntityDescription entityForName:@"ContactInfo" inManagedObjectContext:context];

    [fetchRequest setEntity:entity];

    NSError *error;

    NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];

    for (NSManagedObject *info in fetchedObjects) {

        NSLog(@"classID:%d", [info valueForKey:@"classID"]);

        NSLog(@"persons:%d", [info valueForKey:@"persons"]);

        NSLog(@"name:%@", [info valueForKey:@"name"]);

        NSManagedObject *details = [info valueForKey:@"name"];

        NSLog(@"age:%d", [details valueForKey:@"age"]);

         NSLog(@"classID:%d", [details valueForKey:@"classID"]);

    }

}


fetchRequest相当于sql查询语句的包装类,需要用setEntity方法,来指定具体查询的实体结构(表结构)

通过NSEntityDescription的entityForName方法来,返回指向该具体实体结构的指针

然后调用executeFetchRequest:error:方法,来执行查询操作,如果操作成功,则返回对应的数据记录数组

其中,可以通过NSManagedObject数据记录对象里关联的属性,查询另一个数据记录对象里的属性


之前用Key-Value的代码就可以修改为:

#import "School.h"

#import "Student.h"


- (void)insertCoreData

{

    NSManagedObjectContext *context = [self managedObjectContext];

    

    ContactInfo *contactInfo = [NSEntityDescription insertNewObjectForEntityForName:@"School"inManagedObjectContext:context];

    contactInfo.name = @"name B";

    contactInfo.birthday = @"classID 0";

    contactInfo.age = @"persons 20";

    

    ContactDetailInfo *contactDetailInfo = [NSEntityDescription insertNewObjectForEntityForName:@"Student"inManagedObjectContext:context];

    contactDetailInfo.address = @"age 22";

    contactDetailInfo.name = @"name B";

    contactDetailInfo.telephone = @"classID 1";

    

    contactDetailInfo.info = contactInfo;

    contactInfo.details = contactDetailInfo;

    

    NSError *error;

    if(![context save:&error])

    {

        NSLog(@"不能保存:%@",[error localizedDescription]);

    }

}


- (void)dataFetchRequest

{

    NSManagedObjectContext *context = [self managedObjectContext];

    NSFetchRequest *fetchRequest = [[[NSFetchRequest alloc] init] autorelease];

    NSEntityDescription *entity = [NSEntityDescription entityForName:@"ContactInfo" inManagedObjectContext:context];

    [fetchRequest setEntity:entity];

    NSError *error;

    NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];

    for (Student *info in fetchedObjects) {

        

        NSLog(@"name:%@", info.name);

        NSLog(@"age:%d", info.age);

        NSLog(@"classID:%@", classID);

        School *details = info.details;

        NSLog(@"persons:%d", details.persons);

         NSLog(@"classID:%d", details.classID);

    }

}


1.3.6 数据库相关


1)打印隐藏的sql语句:

在Edit Scheme中选择Run,之后进入Arguments标签,添加参数:“-com.apple.CoreData.SQLDebug 1”

2)使用SQLite存储时,数据库结构

存储的SQLite数据库表名称:大写“Z”加上实体名称大写,一个实体相当于一张表

具体的字段名称:大写“Z”加上实体属性名称大写

2.SQLite


mac os x中SQLite库,它是一个轻量级功能强大的关系数据引擎,也很容易嵌入到应用程序。可以在多个平台使用,SQLite是一个轻量级的嵌入式sql数据库编程。与core data框架不同的是,SQLite是使用程序式的,sql的主要的API来直接操作数据表

 

SQLite3是一个非常灵活的数据库系统,没有数据库服务器的概念,这应该算是回归了比较传统的数据库设计。

早期我们的数据都是直接存放在文件系统,由于简单的文件系统存在数据冗余、不一致、读取操作繁琐(每个数据结构都可能要编写自己的读写程序)等,慢慢形成了数据库管理系统,一套完整的数据库理论。

目前较为流行的Oracle, SqlServer, MySql等数据库系统均是服务器-客户端的概念,数据库服务器负责所有的数据管理、权限管理等,客户端按照一定格式发出请求即可。

sql则是较为流行的结构化查询语言,为众多上层应用提供简单方便的数据库读写操作等。

但是可想而知,服务器端必定是需要对sql请求进行解析然后执行的,那么这些执行程序还得回归更底层的语言,比如C&C++的实现。


注意:

 第1代语言 机器语言(指令系统)其指令为二进制代码(0、1),直接对应芯片上的运算了

 第2代语言 汇编语言 用“助记符”代替二进制代码,如用ADD  A,B表示两数相加。

 第3代语言 高级语言(面向过程)例如:C、JAVA、C++。

 第4代语言(非过程化语言)    例如:SQL语言。

 第5代语言(智能化语言)    例如:Prolog语言)

 

 而SQLite3从功能上来说,这是一个数据库系统,其本质上是由一套用C语言实现的对数据库文件的读写接口。此类接口支持sql语言。所以,这不需要什么服务器,也没有数据库权限管理。在程序中可以随时调用API创建一个数据库文件,进行数据存储,非常灵活易用。


2.1 建立SQLite3.0数据库

在Firefox中打开SQLite3(如果没有,选择工具->附加组件,添加即可)新建SQLite3数据库,Contacts,

建立一个members表,字段 id,integer,主键,自增;name,varchar;email,varchar,null;birthday,datetime,null。

向表中添加一些数据:

pastedGraphic_11.pdf 

 

2.2 SQLite使用代码 


新建Empty Appliation,添加一个HomeViewController,和一个组件libSQLite3.dylib,来支持对SQLite3的连接,关闭,增删改查等操作。

1.)HomeViewController.h代码:

#import

#import "SQLite3.h"


@interface HomeViewController : UIViewController{


    SQLite3 *db; //声明一个SQLite3数据库

}


- (NSString *)filePath;//数据库文件的路径。一般在沙箱的Documents里边操作


@end


 

2.)HomeViewController.m代码:

 #import "HomeViewController.h"



@interface HomeViewController ()


@end



@implementation HomeViewController


//该方法用于返回数据库在Documents文件夹中的全路径信息 

- (NSString *)filePath{


    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

    NSString *documentsDir = [paths objectAtIndex:0];

    return [documentsDir stringByAppendingPathComponent:@"Contacts.SQLite"];

}


//打开数据库的方法 

- (void)openDB{


    if (SQLite3_open([[self filePath] UTF8String], &db) != SQLite_OK) {

        SQLite3_close(db);

        NSAssert(0, @"数据库打开失败。");

    }

}


//插入数据方法

- (void)insertRecordIntoTableName:(NSString *)tableName

                       withField1:(NSString *)field1 field1Value:(NSString *)field1Value

                        andField2:(NSString *)field2 field2Value:(NSString *)field2Value

                        andField3:(NSString *)field3 field3Value:(NSString *)field3Value{

 

   //方法2:变量的绑定方法 

    NSString *sql = [NSString stringWithFormat:@"INSERT INTO ‘%@‘ (‘%@‘, ‘%@‘, ‘%@‘) VALUES (?, ?, ?)",tableName, field1, field2, field3];

    

    SQLite3_stmt *statement;

    

    if (SQLite3_prepare_v2(db, [sql UTF8String], -1, &statement, nil) == SQLite_OK) {

        SQLite3_bind_text(statement, 1, [field1Value UTF8String], -1,NULL);

        SQLite3_bind_text(statement, 2, [field2Value UTF8String], -1,NULL);

        SQLite3_bind_text(statement, 3, [field3Value UTF8String], -1,NULL);

    }

    if (SQLite3_step(statement) != SQLite_DONE) {

        NSAssert(0, @"插入数据失败!");

        SQLite3_finalize(statement);

    }


                                

}

 

//查询数据

- (void)getAllContacts{


    NSString *sql = @"SELECT * FROM members";

    SQLite3_stmt *statement;

    

    if (SQLite3_prepare_v2(db, [sql UTF8String], -1, &statement, nil) == SQLite_OK) {

        while (SQLite3_step(statement) == SQLite_ROW) {

            

            char *name = (char *)SQLite3_column_text(statement, 0);

            NSString *nameStr = [[NSString alloc] initWithUTF8String:name];

            

            char *email = (char *)SQLite3_column_text(statement, 1);

            NSString *emailStr = [[NSString alloc] initWithUTF8String:email];

            

            char *birthday = (char *)SQLite3_column_text(statement, 2);

            NSString *birthdayStr = [[NSString alloc] initWithUTF8String:birthday];

            

            NSString *info = [[NSString alloc] initWithFormat:@"%@ - %@ - %@",

                              nameStr, emailStr, birthdayStr];

            

            NSLog(info);

            

            [nameStr release];

            [emailStr release];

            [birthdayStr release];

            [info release];

        }

        SQLite3_finalize(statement);

    }

}


- (void)viewDidLoad

{

    [self openDB];

   

    [self insertRecordIntoTableName:@"members" withField1:@"name" field1Value:@"李1" andField2:@"email" field2Value:@"df@qq.com" andField3:@"birthday" field3Value:@"12-45-78"];

    

    [self insertRecordIntoTableName:@"members" withField1:@"name" field1Value:@"李2" andField2:@"email" field2Value:@"df@qq.com" andField3:@"birthday" field3Value:@"12-45-78"];

    [self insertRecordIntoTableName:@"members" withField1:@"name" field1Value:@"李3" andField2:@"email" field2Value:@"df@qq.com" andField3:@"birthday" field3Value:@"12-45-78"];

    [self getAllContacts];

    SQLite3_close(db);

    [super viewDidLoad];

}


@end


插入数据后的效果:

 pastedGraphic_12.pdf


查询的效果:


pastedGraphic_13.pdf 

 

 

2.3 小结:

  数据查询:SQLite3_exec()函数执行sql语句,在没有返回值的情况下(比如创建表格、插入记录、删除记录等操作中)很好用。

                 也会用到SQLite3_stat结构、SQLite3_prepare_v2()函数、sqlte3_step()函数和SQLite3_finalize()函数。

   查询分三个阶段:准备阶段:SQLite3_stat、SQLite3_prepare_v2()

       执行阶段:sqlte3_step()

     终止阶段: SQLite3_finalize()

3.FMDB


FMDB框架其实只是一层很薄的封装,主要的类也就两个:FMDatabase和FMResultSet。在使用FMDB的时候还需要导入libSQLite3.0.dylib。


       iOS中原生的SQLite API在使用上相当不友好,在使用时,非常不便。于是,就出现了一系列将SQLite API进行封装的库,例如FMDB、PlausibleDatabase、SQLitepersistentobjects等,FMDB (https://github.com/ccgus/FMDB) 是一款简洁、易用的封装库,这一篇文章简单介绍下FMDB的使用。

在FMDB下载文件后,工程中必须导入如下文件,并使用 libSQLite3.dylib 依赖包。



pastedGraphic_14.pdf



FMDB同时兼容ARC和非ARC工程,会自动根据工程配置来调整相关的内存管理代码。

FMDB常用类:

FMDatabase : 一个单一的SQLite数据库,用于执行SQL语句。
FMResultSet :执行查询一个FMDatabase结果集,这个和android的Cursor类似。
FMDatabaseQueue :在多个线程来执行查询和更新时会使用这个类。


3.1 数据基本操作

1) 创建数据库:


db [FMDatabase databaseWithPath:database_path];  



         1、当数据库文件不存在时,FMDB会自己创建一个。

         2、 如果你传入的参数是空串:@"" ,则FMDB会在临时文件目录下创建这个数据库,数据库断开连接时,数据库文件被删除。

         3、如果你传入的参数是 NULL,则它会建立一个在内存中的数据库,数据库断开连接时,数据库文件被删除。


2) 打开数据库:



[db open]  


返回BOOL型。


3) 关闭数据库:



[db close]  




3.2 数据库增删改等操作:


除了查询操作,FMDB数据库操作都执行executeUpdate方法,这个方法返回BOOL型。


看一下例子:


1)创建表:



if ([db open])  

        NSString *sqlCreateTable  [NSString stringWithFormat:@"CREATE TABLE IF NOT EXISTS ‘%@‘ (‘%@‘ INTEGER PRIMARY KEY AUTOINCREMENT, ‘%@‘ TEXT, ‘%@‘ INTEGER, ‘%@‘ TEXT)",TABLENAME,ID,NAME,AGE,ADDRESS];

  

        BOOL res [db executeUpdate:sqlCreateTable];  


        if (!res)  


            NSLog(@"error when creating db table");

  

        else  


            NSLog(@"success to creating db table");  

         


        [db close];  

 





2)添加数据:



if ([db open])  

       NSString *insertSql1= [NSString stringWithFormat:  

                              @"INSERT INTO ‘%@‘ (‘%@‘, ‘%@‘, ‘%@‘) VALUES (‘%@‘, ‘%@‘, ‘%@‘)",  TABLENAME, NAME, AGE, ADDRESS, @"张三"@"13"@"济南"];  


       BOOL res [db executeUpdate:insertSql1];  

       NSString *insertSql2 [NSString stringWithFormat:  

                               @"INSERT INTO ‘%@‘ (‘%@‘, ‘%@‘, ‘%@‘) VALUES (‘%@‘, ‘%@‘, ‘%@‘)",TABLENAME, NAME, AGE, ADDRESS, @"李四"@"12"@"济南"];  


       BOOL res2 [db executeUpdate:insertSql2];  

         

       if (!res)  


           NSLog(@"error when insert db table"); 

 

       else  


           NSLog(@"success to insert db table");  

        


       [db close];  

  

 


3)修改数据:




if ([db open])  

        NSString *updateSql [NSString stringWithFormat:  

                               @"UPDATE ‘%@‘ SET ‘%@‘ ‘%@‘ WHERE ‘%@‘ ‘%@‘",TABLENAME,   AGE,  @"15" ,AGE,  @"13"]; 


        BOOL res [db executeUpdate:updateSql]; 

 

        if (!res)  

            NSLog(@"error when update db table");  

        else  

            NSLog(@"success to update db table");  

         

        [db close];  

  

   

4)删除数据:



if ([db open])  

          

        NSString *deleteSql [NSString stringWithFormat:  

                               @"delete from %@ where %@ ‘%@‘" 

                               TABLENAME, NAME, @"张三"];  

        BOOL res [db executeUpdate:deleteSql];  

          

        if (!res)  

            NSLog(@"error when delete db table");  

        else  

            NSLog(@"success to delete db table");  

         

        [db close];  

  

   




5)数据库查询操作:

查询操作使用了executeQuery,并涉及到FMResultSet。



if ([db open])  

        NSString sql [NSString stringWithFormat:  

                          @"SELECT FROM %@",TABLENAME];  

        FMResultSet rs [db executeQuery:sql];  

        while ([rs next])  

            int Id [rs intForColumn:ID];  

            NSString name [rs stringForColumn:NAME];  

            NSString age [rs stringForColumn:AGE];  

            NSString address [rs stringForColumn:ADDRESS];  

            NSLog(@"id %d, name %@, age %@  address %@", Id, name, age, address);  

         

        [db close];  

  



FMDB的FMResultSet提供了多个方法来获取不同类型的数据:







3.3 数据库多线程操作:


        如果应用中使用了多线程操作数据库,那么就需要使用FMDatabaseQueue来保证线程安全了。 应用中不可在多个线程中共同使用一个FMDatabase对象操作数据库,这样会引起数据库数据混乱。 为了多线程操作数据库安全,FMDB使用了FMDatabaseQueue,使用FMDatabaseQueue很简单,首先用一个数据库文件地址来初使化FMDatabaseQueue,然后就可以将一个闭包(block)传入inDatabase方法中。 在闭包中操作数据库,而不直接参与FMDatabase的管理。



FMDatabaseQueue queue [FMDatabaseQueue databaseQueueWithPath:database_path];  

   dispatch_queue_t q1 dispatch_queue_create("queue1"NULL);  

   dispatch_queue_t q2 dispatch_queue_create("queue2"NULL);  

     

   dispatch_async(q1, ^{  

       for (int 0; 50; ++i)  

           [queue inDatabase:^(FMDatabase *db2)  

                 

               NSString *insertSql1= [NSString stringWithFormat:  

                                      @"INSERT INTO ‘%@‘ (‘%@‘, ‘%@‘, ‘%@‘) VALUES (?, ?, ?)" 

                                      TABLENAME, NAME, AGE, ADDRESS];  

                 

               NSString name [NSString stringWithFormat:@"jack %d"i];  

               NSString age [NSString stringWithFormat:@"%d"10+i];  

                 

                 

               BOOL res [db2 executeUpdate:insertSql1, name, age,@"济南"];  

               if (!res)  

                   NSLog(@"error to inster data: %@"name);  

               else  

                   NSLog(@"succ to inster data: %@"name);  

                

           }];  

        

   });  

     

   dispatch_async(q2, ^{  

       for (int 0; 50; ++i)  

           [queue inDatabase:^(FMDatabase *db2)  

               NSString *insertSql2= [NSString stringWithFormat:  

                                      @"INSERT INTO ‘%@‘ (‘%@‘, ‘%@‘, ‘%@‘) VALUES (?, ?, ?)" 

                                      TABLENAME, NAME, AGE, ADDRESS];  

                 

               NSString name [NSString stringWithFormat:@"lilei %d"i];  

               NSString age [NSString stringWithFormat:@"%d"10+i];  

                 

               BOOL res [db2 executeUpdate:insertSql2, name, age,@"北京"];  

               if (!res)  

                   NSLog(@"error to inster data: %@"name);  

               else  

                   NSLog(@"succ to inster data: %@"name);  

                

           }];  

        

   });  



4.总结


  • CoreData允许用户使用代表实体和实体间关系的高层对象来操作数据。它也可以管理串行化的数据,提供对象生存期管理与object_graph 管理,包括存储。Core Data直接与SQLite交互,避免开发者使用原本的SQL语句.


  • 上面的三种,都是在什么情况下使用呢?大多数人肯定是根据自己使用某项技术的时间也就是掌握的熟练程度来决定,例如以前没用过CoreData,在编写ios程序的时候还是使用自己比较拿手的SQLite,或者可能会考虑到在使用coredata自己还要花费额外的时候去学习。


  • 但是仔细想一想,CoreData是苹果自己弄的框架,它其实还是和SQLite进行交互的,只是在交互的时候或者处理数据的时候进行了很多的优化,CoreData可以缩小你的代码量,而且CoreData已经优化过很多个版本,还提供了出色的安全性和错误处理之外,还提供了对任何竞争性方案的最好的内存可扩展性。换句话说就是,你可能花费了很长时间为某个问题进行优化精心制作了一个方案,但是在性能上的优势和CoreData相比,还是相差深远的。


  • 另外就是CoreData与Mac OS X的集成非常的好,CoreData也和IB进行了结合,允许你创建用户界面,这样可以帮助你缩短应用程序的设计,实施以及调试周期。


  • 所以在编写程序的时候尽量使用CoreData,这样才是最优的选择。只有在Core Data is available on iOS 3.0 and later才能使用CoreData。


  • 至于SQLite和FMDB的使用情况,这个看个人喜好了,个人觉得没什么标准。FMDB就是对SQLite的封装,使用起来有方便的接口,没那么麻烦而已。

数据持久化-CoreData、SQLite、FMDB