一. 什么是FMDB ?
iOS中使用C语言函数对原生SQLite数据库进行增删改查操作,复杂麻烦,于是,就出现了一系列将SQLite API封装的库,如FMDB
FMDB是针对libsqlite3框架进行封装的三方,它以OC的方式封装了SQLite的C语言的API,使用步骤与SQLite相似
FMDB的优点是:
(1) 使用时面向对象,避免了复杂的C语言代码
(2) 对比苹果自带的Core Data框架,更加轻量级和灵活
(3) 提供多线程安全处理数据库操作方法,保证多线程安全跟数据准确性
FMDB缺点:
(1) 因为是OC语言开发,只能在iOS平台上使用,所以实现跨平台操作时存在限制性
FMDB 在Git上的下载链接地址: https://github.com/ccgus/fmdb
二. 主要类型
FMDatabase:一个FMDatabase对象代表一个单独的SQLite数据库,通过SQLite语句执行数据库的增删改查操作
FMResultSet:使用FMDatabase对象查询数据库后的结果集
FMDatabaseQueue:用于多线程操作数据库,它保证线程安全-----官方建议使用这个,线程安全的
FMDB是针对libsqlite3框架进行封装的三方,它以OC的方式封装了SQLite的C语言的API,使用步骤与SQLite相似
FMDB的优点是:
(1) 使用时面向对象,避免了复杂的C语言代码
(2) 对比苹果自带的Core Data框架,更加轻量级和灵活
(3) 提供多线程安全处理数据库操作方法,保证多线程安全跟数据准确性
FMDB缺点:
(1) 因为是OC语言开发,只能在iOS平台上使用,所以实现跨平台操作时存在限制性
FMDB 在Git上的下载链接地址: https://github.com/ccgus/fmdb
二. 主要类型
FMDatabase:一个FMDatabase对象代表一个单独的SQLite数据库,通过SQLite语句执行数据库的增删改查操作
FMResultSet:使用FMDatabase对象查询数据库后的结果集
FMDatabaseQueue:用于多线程操作数据库,它保证线程安全-----官方建议使用这个,线程安全的
/*
* FMDatabaseQueue使用案例
*/
- (void)FMDatabaseQueueTest{
//1、获取数据库文件路径
NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *fileName = [doc stringByAppendingPathComponent:@"students.sqlite"];
//使用
FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:fileName];
[queue inDatabase:^(FMDatabase *db) {
[db executeUpdate:@"CREATE TABLE IF NOT EXISTS t_student_2 (id integer PRIMARY KEY AUTOINCREMENT, name text NOT NULL, age integer NOT NULL);"];
[db executeUpdate:@"INSERT INTO t_student_2 (name, age) VALUES ('yixiangZZ', 20);"];
[db executeUpdate:@"INSERT INTO t_student_2 (name, age) VALUES ('yixiangXX', 25);"];
FMResultSet *rs = [db executeQuery:@"SELECT * FROM t_student_2"];
NSLog(@"%@",[NSThread currentThread]);
while ([rs next]) {
int ID = [rs intForColumn:@"id"];
NSString *name = [rs stringForColumn:@"name"];
int age = [rs intForColumn:@"age"];
NSLog(@"%d %@ %d",ID,name,age);
}
}];
//支持事务
[queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
[db executeUpdate:@"UPDATE t_student_2 SET age = 40 WHERE name = 'yixiangZZ'"];
[db executeUpdate:@"UPDATE t_student_2 SET age = 45 WHERE name = 'yixiangXX'"];
BOOL hasProblem = NO;
if (hasProblem) {
*rollback = YES;//回滚
return;
}
FMResultSet *rs = [db executeQuery:@"SELECT * FROM t_student_2"];
NSLog(@"%@",[NSThread currentThread]);
while ([rs next]) {
int ID = [rs intForColumn:@"id"];
NSString *name = [rs stringForColumn:@"name"];
int age = [rs intForColumn:@"age"];
NSLog(@"%d %@ %d",ID,name,age);
}
}];
}
/**
* FMDatabaseQueue如何实现多线程的案例
*/
- (void)FMDatabaseQueueMutilThreadTest{
//1、获取数据库文件路径
NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *fileName = [doc stringByAppendingPathComponent:@"students.sqlite"];
//使用queue1
FMDatabaseQueue *queue1 = [FMDatabaseQueue databaseQueueWithPath:fileName];
[queue1 inDatabase:^(FMDatabase *db) {
for (int i=0; i<10; i++) {
NSLog(@"queue1---%zi--%@",i,[NSThread currentThread]);
}
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[queue1 inDatabase:^(FMDatabase *db) {
for (int i=11; i<20; i++) {
NSLog(@"queue1---%zi--%@",i,[NSThread currentThread]);
}
}];
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[queue1 inDatabase:^(FMDatabase *db) {
for (int i=20; i<30; i++) {
NSLog(@"queue1---%zi--%@",i,[NSThread currentThread]);
}
}];
});
//虽然开启了多个线程,可依然还是串行处理。原因如下:
/**FMDatabaseQueue虽然看似一个队列,实际上它本身并不是,它通过内部创建一个Serial的dispatch_queue_t来处理通过inDatabase和inTransaction传入的Blocks,所以当我们在主线程(或者后台)调用inDatabase或者inTransaction时,代码实际上是同步的。FMDatabaseQueue这么设计的目的是让我们避免发生并发访问数据库的问题,因为对数据库的访问可能是随机的(在任何时候)、不同线程间(不同的网络回调等)的请求。内置一个Serial队列后,FMDatabaseQueue就变成线程安全了,所有的数据库访问都是同步执行,而且这比使用@synchronized或NSLock要高效得多。
*/
}