面试题答案
一键面试FMDB在多线程环境下的问题
- 资源竞争:多个线程同时访问和修改数据库,可能导致数据不一致。例如,一个线程正在读取数据,另一个线程同时进行写入操作,可能会使读取的数据不准确。
- 数据库锁争用:数据库在同一时间只能处理有限的操作,多个线程频繁请求数据库操作可能导致锁争用,降低性能。
- 内存管理问题:如果多个线程同时对数据库连接进行操作,可能导致内存管理混乱,如连接泄漏等问题。
使用FMDatabaseQueue解决问题
FMDatabaseQueue
是FMDB提供的用于在多线程环境下安全操作数据库的类。它内部使用了GCD(Grand Central Dispatch)来管理队列,确保数据库操作顺序执行,避免资源竞争。
代码示例
假设我们有一个简单的用户信息表,包含name
和age
字段,下面是使用FMDatabaseQueue
进行插入和查询操作的示例代码:
#import <UIKit/UIKit.h>
#import "FMDatabase.h"
#import "FMDatabaseQueue.h"
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) FMDatabaseQueue *databaseQueue;
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// 初始化数据库路径
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
NSString *databasePath = [documentsPath stringByAppendingPathComponent:@"test.db"];
// 创建FMDatabaseQueue实例
self.databaseQueue = [FMDatabaseQueue databaseQueueWithPath:databasePath];
// 示例:插入数据
[self.databaseQueue inDatabase:^(FMDatabase *db) {
NSString *insertSQL = @"INSERT INTO users (name, age) VALUES (?,?)";
[db executeUpdate:insertSQL, @"John", @25];
}];
// 示例:查询数据
[self.databaseQueue inDatabase:^(FMDatabase *db) {
FMResultSet *resultSet = [db executeQuery:@"SELECT name, age FROM users"];
while ([resultSet next]) {
NSString *name = [resultSet stringForColumn:@"name"];
NSInteger age = [resultSet intForColumn:@"age"];
NSLog(@"Name: %@, Age: %ld", name, (long)age);
}
}];
return YES;
}
@end
上述代码中:
- 首先通过
[FMDatabaseQueue databaseQueueWithPath:databasePath]
创建了FMDatabaseQueue
实例。 - 使用
inDatabase:
方法在队列中执行数据库操作。在inDatabase:
块内,FMDatabaseQueue
会自动获取数据库连接并在操作完成后释放连接,确保操作顺序执行,避免多线程问题。无论是插入操作还是查询操作,都在这个块内安全地执行。