【发布时间】:2013-11-22 12:10:01
【问题描述】:
我有一个使用 sqlite 3.6(不使用 FMDB)来存储和加载数据的 iPhone 应用程序。当应用程序加载并在整个应用程序中使用相同的数据库连接时,我会加载数据库。
在后台线程中,应用程序从网络服务器下载一些数据并写入数据库。同时主线程也可能需要写入同一个数据库。这有时会导致 EXC_BAD_ACCESS,因为两个线程都在尝试访问数据库。
从不同线程使用数据库的最佳和最简单的方法是什么?
这是一个说明问题的例子:
sqlite3 *database;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:@"database.db"];
if (sqlite3_open([path UTF8String], &database) != SQLITE_OK) {
sqlite3_close(database);
return YES;
}
[NSThread detachNewThreadSelector:@selector(test) toTarget:self withObject:nil];
[self test];
return YES;
}
-(void)test {
for (int i = 0; i < 2000; i++) {
NSLog(@"%i",i);
sqlite3_exec([self getDb],"UPDATE mytable SET test=''", 0, 0, 0);
}
}
编辑:
在下面 willcodejavaforfood 的回答之后,我尝试更改我的代码以对每个单独的线程使用单独的数据库对象(连接),并添加 sqlite3_busy_timeout() 以便如果数据库忙,sqlite 将重试写入。现在我不再得到 EXC_BAD_ACCESS 但我注意到并非所有数据都被插入。所以这也不是一个稳定的解决方案。让 sqlite 使用线程似乎真的很难..
我使用单独连接的新解决方案:
-(void)test {
sqlite3 *db = [self getNewDb];
for (int i = 0; i < 2000; i++) {
NSLog(@"%i",i);
sqlite3_exec(db,"UPDATE mytable SET test=''", 0, 0, 0);
}
}
- (sqlite3 *)getNewDb {
sqlite3 *newDb = nil;
if (sqlite3_open([[self getDbPath] UTF8String], &newDb) == SQLITE_OK) {
sqlite3_busy_timeout(newDb, 1000);
} else {
sqlite3_close(newDb);
}
return newDb;
}
【问题讨论】:
标签: iphone multithreading sqlite