FMDB
来源:互联网 发布:apply js 编辑:程序博客网 时间:2024/05/22 06:25
FMDB
一、FMDB简介
FMDB是iOS平台的SQLite数据库框架,它以OC的方式封装了SQLite的C语言API,github地址是https://github.com/ccgus/fmdb。
FMDB的优点:
1. 使用起来更加面向对象,省去了很多麻烦、冗余的C语言代码
2. 对比苹果自带的Core Data框架,更加轻量级和灵活
3. 提供了多线程安全的数据库操作方法,有效地防止数据混乱
FMDB有三个主要的类
1. FMDatabase。一个FMDatabase对象就代表一个单独的SQLite数据库,用来执行SQL语句
2. FMResultSet。使用FMDatabase执行查询后的结果集。
3. FMDatabaseQueue。用于在多线程中执行多个查询或更新,它是线程安全的。
在FMDB中,除查询以外的所有操作,都称为“更新”,包括:create、drop、insert、update、delete等。
二、FMDatabase
使用前,需要下载FMDB框架,并导入src下的fmdb文件夹。之后还需要在项目中添加sqlite3.dylib,并在程序文件中导入FMDB.h。
2.1 创表
获取到sqlite文件路径path之后:
@property (nonatomic, strong) FMDatabase *db;//创建数据库实例对象self.db = [FMDatabase databaseWithPath:path];//打开数据库if (![self.db open]) { NSLog(@"打开数据库失败");}else { //创表student BOOL result = [self.db executeUpdate:@"create table if not exists t_student (id integer primary key autoincrement, name text unique, age integer not null);"]; if (result) { NSLog(@"创表成功"); }else { NSLog(@"创表失败"); }}
2.2 增删改查
//插入数据BOOL result = [self.db executeUpdate:@"insert into t_class (name) values(?)", @"Steven"];//删除数据,注意int等基本数据类型需要转为NSNumberBOOL result1 = [self.db executeUpdate:@"delete from t_student where id = ", @10];//更改数据BOOL result2 = [self.db executeUpdate:@"update t_student set ame = ? where id = ?", @"Sally", @100];//查询数据//注意查询和增删改、创表等操作都不一样,它执行的executeQuery方法FMResultSet *resultSet = [self.db executeQuery:@"select * from t_student where id = ? or id = ?", @10, @11];while (resultSet.next) { int ID = [resultSet intForColumn:@"ID"]; NSString *name = [resultSet stringForColumn:@"name"]; int age = [resultSet intForColumn:@"age"]; NSLog(@"%d, %@, %d", ID, name, age);}
2.3 外键、count
和使用原声的SQLite API一样,在FMDB中使用外键同样需要使用代码开启,不一样的是,FMDB中只需要在打开数据库的时候开启一次即可。在上一篇博客中介绍了多表关联、级联更新等内容,这里不再介绍,直接贴上开启外键的语句即可。
//开启外键BOOL openfk = [self.db executeUpdate:@"PRAGMA foreign_keys = ON"];
计数:
int count = 0;FMResultSet *resultSet = [self.db executeQuery:@"select count(*) from t_student where id > 8"];if (resultSet.next) { count = [resultSet intForColumnIndex:0]; NSLog(@"count-->%d", count);}
三、FMDatabaseQueue
FMDatabase这个类是线程不安全的,如果在多个线程中同时使用一个FMDatabase实例,会造成数据混乱等问题。为了保证线程安全,FMDB提供方便快捷的FMDatabaseQueue类。
3.1 创表
获取到数据库文件路径path后:
@property (nonatomic, strong) FMDatabaseQueue *queue; //创建数据库队列 //数据库同时也会被创建并打开 self.queue = [FMDatabaseQueue databaseQueueWithPath:path]; //创建表 [self.queue inDatabase:^(FMDatabase *db) { //创表student BOOL result = [db executeUpdate:@"create table if not exists t_student (id integer primary key autoincrement, name text, age integer);"]; if (result) { NSLog(@"创表成功"); }else { NSLog(@"创表失败"); } }];
3.2 查询数据
增删改查的使用方法和创表差不多,这里只贴上查询数据的方法:
[self.queue inDatabase:^(FMDatabase *db) { FMResultSet *resultSet = [db executeQuery:@"select * from t_student where id = ?", @1]; while (resultSet.next) { NSString *name = [resultSet stringForColumn:@"name"]; int age = [resultSet intForColumn:@"age"]; NSLog(@"name-->%@, age-->%d", name, age); } }];
四、测试FMDatabase和FMDatabaseQueue
FMDatabaseQueue是线程安全的,但光这么说难以形象的知道它和FMDatabase存在的差异,因此特地写几行代码测试一下。
dispatch_queue_t q = dispatch_queue_create("testUpdate", DISPATCH_QUEUE_CONCURRENT); for (int i=0; i<10; i++) { dispatch_async(q, ^{ //测试FMDatabaseQueue时,把里面的代码放进[self.queue inDatabase:^(FMDatabase *db) { }];里面执行// [self.queue inDatabase:^(FMDatabase *db) { BOOL result1 = [self.db executeUpdate:@"update t_student set name = ? where id = ?", @"Alice", @10]; BOOL result2 = [self.db executeUpdate:@"update t_student set name = ? where id = ?", @"Sally", @10]; BOOL result3 = [self.db executeUpdate:@"update t_student set name = ? where id = ?", @"Steven", @10]; BOOL result4 = [self.db executeUpdate:@"update t_student set name = ? where id = ?", @"Hayley", @10]; if (result1) { NSLog(@"%@-----result1更新成功", [NSThread currentThread]); }else { NSLog(@"%@-----result1更新失败, %@", [NSThread currentThread], [self.db lastErrorMessage]); } if (result2) { NSLog(@"%@-----result2更新成功", [NSThread currentThread]); }else { NSLog(@"%@-----result2更新失败, %@", [NSThread currentThread], [self.db lastErrorMessage]); } if (result3) { NSLog(@"%@-----result3更新成功", [NSThread currentThread]); }else { NSLog(@"%@-----result3更新失败, %@", [NSThread currentThread], [self.db lastErrorMessage]); } if (result4) { NSLog(@"%@-----result4更新成功", [NSThread currentThread]); }else { NSLog(@"%@-----result4更新失败, %@", [NSThread currentThread], [self.db lastErrorMessage]); }// }]; });
上面的代码开启了一个并行序列,并异步执行里面的代码。
如果使用的是FMDatabase,打印结果如图:
可以看到,程序运行期间会发生资源抢夺的问题,并且执行顺序是无序的。
换成FMDatabaseQueue,打印结果如图:
可以看到,程序运行期间代码的执行是有序的,不会发生错误,并且每次执行均在同一个线程内。
进入FMDatabaseQueue.h文件,可以看到作者的注释如下:
FMDatabaseQueue
will run the blocks on a serialized queue (hence the name of the class). So if you callFMDatabaseQueue
’s methods from multiple threads at the same time, t**hey will be executed in the order they are received**. This way queries and updates won’t step on each other’s toes, and every one is happy.@warning The calls to
FMDatabaseQueue
’s methods are blocking. So even though you are passing along blocks, they will **not** be run on another thread.
简单的说,就是作者把FMDatabaseQueue写死了,代码一定会在串行序列里执行,每次执行都只会创建一个线程,不会有多个线程同时抢夺同一个资源的问题发生。
五、事务
程序对数据库的操作不一定是独立的,有些时候,你会希望程序中的某些代码要么都执行成功,要么都执行失败。这种情况下,就应该使用事务。
5.1 使用方法(一)
[self.db beginTransaction]; [self.db executeUpdate:@"update t_student set name = ? where id = ?", @"Alice3", @10]; //故意把name写成ame BOOL result2 = [self.db executeUpdate:@"update t_student set ame = ? where id = ?", @"Sally", @100]; if (!result2){ NSLog(@"更新失败result2-->%@", [self.db lastErrorMessage]); [self.db rollback]; } [self.db executeUpdate:@"update t_student set name = ? where id = ?", @"Steven3", @11]; [self.db commit];
上面的代码中, 因为第二个更新操作是错误的,这时候程序执行rollback方法,所以前面第一个更新操作会被撤回,不更新。第3个更新操作之后未执行rollback方法,所以不撤销,更新成功。
5.2 使用方法(二)
在FMDatabaseQueue中,事务的使用方法如下
[self.queue inTransaction:^(FMDatabase *db, BOOL *rollback) { BOOL result = [db executeUpdate:@"update t_student set name = ? where id = ?", @"Alice", @1]; if (result) { NSLog(@"更新成功"); }else { NSLog(@"更新失败, %@", [db lastErrorMessage]); *rollback = YES; }}];
六、总结
FMDB有三个主要的类
1. FMDatabase。一个FMDatabase对象就代表一个单独的SQLite数据库,用来执行SQL语句
2. FMResultSet。使用FMDatabase执行查询后的结果集。
3. FMDatabaseQueue。用于在多线程中执行多个查询或更新,它是线程安全的。
如果希望某些代码要么都执行成功,要么都执行失败,应该使用事务。
- FMDB
- FMDB
- FMDB
- FMDB
- FMDB
- fmdb
- FMDB
- FMDB
- fmdb
- FMDB
- FMDB
- fmdb
- FMDB
- FMDB
- FMDB
- FMDB
- FMDB
- FMDB
- 安卓开发学习心得-------Spinner基础
- git服务器bitnami一键安装
- 大数据基础(四)Ubuntu sbt安装和Spark下的使用
- C#中静态变量的初始化
- 开发2年后我在想什么
- FMDB
- 十四届北师大校赛题解
- 【Android官方文档】翻译Android官方文档-Activities(一)
- 安卓开发学习心得-------WebView的使用
- 给TextView添加点击事件的写法
- 清除windows系统垃圾文件简易脚本(bat)
- 编译与调试--adt
- 跟我学习php字符串常用函数-下篇
- #Spring#spring小程序,简单介绍spring的使用