数据持久化之FMDB简单使用

来源:互联网 发布:公民网络身份识别系统 编辑:程序博客网 时间:2024/06/05 08:41

使用第三方库FMDB

1.创建.db文件,并取得路径

-(NSString *)getDBPath{    NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,                                                             NSUserDomainMask, YES) objectAtIndex:0];    NSString *dbPath = [docPath stringByAppendingPathComponent:@"user.db"];    return dbPath;}

2.创建表格,保存数据库

先要打开数据库,创建表,向表中插入数据,再执行更新操作,然后关闭数据库

- (IBAction)saveButtonClicked:(id)sender {    //获取Document文件夹下的数据库文件,没有则创建    NSString *dbPath = [self getDBPath];    FMDatabase *database  = [FMDatabase databaseWithPath:dbPath];    if (![database open]) {        NSLog(@"Open database failed");        return;    }        //创建表    [database executeUpdate:@"create table user (name text,gender text,age integer)"];        //插入数据    BOOL insert = [database                   executeUpdate:@"insert into user values (?,?,?)",                    self.nameTextField.text,self.genderTextField.text,self.ageTextField.text];        if (insert) {        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示"                                                        message:@"保存成功"                                                       delegate:self                                              cancelButtonTitle:@"确定"                                              otherButtonTitles:nil, nil];        [alert show];        [alert release];    }    // 关闭数据库连接    [database close];}

3.查询操作

先打开数据库,执行查询,再关闭数据库

 NSString *dbPath = [self getDBPath];    FMDatabase *database = [FMDatabase databaseWithPath:dbPath];    if (![database open]) {        return;    }        //不需要像Android中那样关闭Cursor关闭FMResultSet,因为相关的数据库关闭时,FMResultSet也会被自动关闭    FMResultSet *resultSet = [database executeQuery:@"select * from user"];
    // 条件查询
<p style="margin-top: 0px; margin-bottom: 0px; font-size: 13px; font-family: Menlo;"><span style="color:#424242;">    // </span><strong>FMResultSet</strong> *resultSet = [database <strong>executeQuery</strong>:@"select * from user where name = ?",@"welfred"];</p>    while ([resultSet next]) {        NSString *name = [resultSet stringForColumn:@"name"];        NSString *gender = [resultSet stringForColumn:@"gender"];        int age = [resultSet intForColumn:@"age"];        NSLog(@"Name:%@,Gender:%@,Age:%d",name,gender,age);    }        [database close];

4.更新

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);    NSString *docPath = [paths objectAtIndex:0];    NSString *dbPath = [docPath stringByAppendingPathComponent:@"user.db"];        FMDatabase *database = [FMDatabase databaseWithPath:dbPath];    if (![database open]) {        return;    }        //参数必须是NSObject的子类,int,double,bool这种基本类型,需要封装成对应的包装类才可以    BOOL update = [database                   executeUpdate:@"update user set name = ? where age = ?",@"RyanTang",                   [NSNumber numberWithInt:24]];    if(update){        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示"                                                        message:@"更新成功"                                                       delegate:self                                              cancelButtonTitle:@"确定"                                              otherButtonTitles:nil, nil];        [alert show];        [alert release];    }    [database close];

5.删除

 NSString *dbPath = [self getDBPath];    FMDatabase *database = [FMDatabase databaseWithPath:dbPath];    if (![database open]) {        return;    }    BOOL delete = [database executeUpdate:@"delete from user where name = ?",@"Tang"];    if (delete) {        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示" message:@"删除成功" delegate:self cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];        [alert show];        [alert release];    }        [database close];

6涉及多线程

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 i = 0; i < 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 i = 0; i < 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);                }            }];        }    });

附:Sqlite中INTEGER PRIMARY KEY AUTOINCREMENT和rowid的使用
参考http://www.cnblogs.com/peida/archive/2008/11/29/1343832.html


在用sqlite设计表时,突然想到一个问题,就是我设计的表中,每个表都有一个自己的整形 id值作为主键,其实可以不指定这么一个id值,sqlite内部本来就会为每个表加上一个 rowid,这个rowid可以当成一个隐含的字段使用,但 是由sqlite引擎来维护的,在3.0以前rowid是32位的整数,3.0以后是64位的整数,为什么不直接使用这个内部的rowid作为每个表的 id主键呢。
想到就立即先查找一下sqlite的文档,看看用指定INTEGER PRIMARY KEY AUTOINCREMENT 和不指定自增长字段用rowid有什么区别。相关的文档在这里:http://www.sqlite.org/autoinc.htmlhttp://www.sqlite.org/faq.html
使用自增长字段为主键有不少问题,比如维护或是在大型分布应用中主键冲突的解决等。在一些大型分布应用中主键一般选用guid,这可以有效的避免主键冲突,减少对主键维护的工程。当然,对于中小型的应用,自增长字段的好处更多一些,简单、快速。
Sqlite中,一个自增长字段定义为INTEGER PRIMARY KEY AUTOINCREMENT  ,那么在插入一个新数据时,只需要将这个字段的值指定为NULL,即可由引擎自动设定其值,引擎会设定为最大的rowid+1。当然,也可以设置为非 NULL的数字来自己指定这个值,但这样就必须自己小心,不要引起冲突。当这个rowid的值大于所能表达的最大值 9223372036854775807 (3.0及以后版本的rowid最大值)后,rowid的新值会这个最大数之前随机找一个没被使用了的值。所以在rowid达到最大值前,rowid的值 是严格单调增加的。
INTEGER PRIMARY KEY AUTOINCREMENT 自增长字段的算法与rowid稍微有些不同。
第一,在达到最大值后,rowid会找已被删除的字段对应的rowid作为新值,而自增长字段则会丢出一个SQLITE_FULL的错误
第二,自增长字段在增加新值时,是找一个从没被使用过的rowid作为新值,而rowid则是找最大已存在的rowid+1。这里对应用的影响会比较大,尤其是一些对id值有依赖的元记录,只适合使用自增长字段而不能用rowid。比如,我们设计一个元记录表:
Create table meta_struct(id INTEGER PRIMARY KEY AUTOINCREMENT, name varchar, type Integer);
然后,定义一个一级表,来描述其它表的结构:
Create table meta_table(tableid INTEGER, table_field integer)
最后,我们的应用可以根据这个一级表来产生实际使用的二级表。 这样为保证兼容性 meta_struct中的id必须是唯一的,如果有字段被删除,也不能重复使用这个字段的id值,不然,在数据库合并时,一级表和二级表就会混乱。所以 meta_struct表中的主键只能使用自增长字段,而不能用rowid。
第三,使用自增 长字段,引擎会自动产生一个sqlite_sequence表,用于记录每个表的自增长字段的已使用的最大值,用户可以看到,并可以用使用Update、 Delete和Insert操作,但不建议这么使用,这会让引擎混乱。如果使用rowid,也会有这么一个内部表,用户可以维护rowid值,但看不到。
这么看来,如果直接使用rowid来代替自增加字段,根据两者的细微的差别,需要注意是否与自己的应用冲突,如果没有冲突,那么用rowid会更快一点。


0 0
原创粉丝点击