У меня есть приложение для iPhone, которое использует sqlite 3.6 (не с FMDB) для хранения и загрузки данных.Я загружаю базу данных, когда приложение загружает и использует одно и то же соединение с базой данных через все приложение.
В фоновом потоке приложение загружает некоторые данные с веб-сервера и записывает их в базу данных.В то же время основной поток также может нуждаться в записи в ту же базу данных.Это иногда приводит к 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;
}