我在我的应用程序中使用了两种不同类型的 fmdb 连接:
FMDatabase 用于所有 READ 查询,FMDatabaseQueue 用于所有 UPDATE 查询。
两者都由单例处理,在应用程序运行时这两种类型都保持打开状态。
读取和更新查询都在不同的线程中使用,因为我的应用程序中的某些任务是在后台进行的;就像从服务器获取数据并在自己的后台线程中通过 FMDatabaseQueue 将其插入数据库一样 - 同时通过 FMDatabase 从数据库读取一些信息并在主线程上使用它更新 ViewController。
我的问题是,通过 FMDatabaseQueue 将数据插入数据库后,第二个连接(FMDatabase)没有返回更新的信息,因为它没有找到它们。但是我知道数据已插入,因为我已经使用数据库浏览器工具检查了数据库 + 插入时没有发生错误。为避免这种情况,我必须关闭 FMDatabase 数据库连接并重新打开它以查看其他连接所做的更改。不幸的是,当我的应用程序启动时,有很多插入、更新 + 读取,因为从需要处理的服务器加载了很多新数据 - 所以每次更新时都会关闭和打开数据库在许多“数据库繁忙”中发生消息。
我之前对所有线程使用了一个 FMDatabaseQueue 并执行(读取、更新),但是当使用带有 __block 变量的读取查询以从回调中获取结果集而另一个线程执行一些插入(在 50-100 之间单笔交易)。
最重要的是,数据库是通过 sqlcipher 加密的——不确定它是否重要但想提及它。所以每次我必须关闭并打开数据库时,我都在做一个 setKey。
我的问题:是否可以在多个线程上使用具有两种不同连接类型的设置,如果可以,我是否必须关闭并打开 FMDatabase 连接?或者这个用例有更好的解决方案吗?
更新
我执行插入/更新的代码看起来像
-(void) create:(NSArray *)transactions
{
NSMutableString *sqlQuery = [[NSMutableString alloc] initWithString:STANDARD_INSERT_QUERY];
[sqlQuery appendString:@"(transaction_id, name, date) VALUES (?,?,?)"];
FMDBDataSource *ds = [FMDBDataSource sharedManager];
FMDatabaseQueue *queue = [ds getFMDBQ];
[queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
[db setKey:[ds getKey]]; // returns the key to decrypt the database
for (Transaction *transaction in transactions)
{
[db executeUpdate:sqlQuery, transaction.transactionId, transaction.name, transaction.date];
}
}];
}
和一个读取查询
-(Transaction *)read:(NSString *)transactionId
{
NSString *sqlQuery = [[NSString alloc] initWithString:STANDARD_SELECT_QUERY];
Transaction *transaction = nil;
FMDBDataSource *ds = [FMDBDataSource sharedManager];
FMResultSet *rs = [[ds getFMDB] executeQuery:sqlQuery];
while ([rs next]) {
transaction = [[Transaction alloc] init];
[transaction setTransactionId:[rs stringForColumn:@"transaction_id"]];
[transaction setName:[rs stringForColumn:@"name"]];
}
[rs close];
return transaction;
}
FMDBDataSource 是一个单例,同时包含 FMDatabase 和 FMDatabaseQueue 连接
- (FMDatabaseQueue *)getFMDBQ
{
if (self.fmdbq == nil)
{
self.fmdbq = [FMDatabaseQueue databaseQueueWithPath:[self getDBPath]];
}
return self.fmdbq;
}
- (FMDatabase *) getFMDB
{
if(self.fmdb == nil)
{
self.fmdb = [FMDatabase databaseWithPath:[self getDBPath]];
[self openAndKeyDatabase]; // opens the db and sets the key as the db is encrypted
}
return self.fmdb;
}
正如我所说,使用此代码时,FMDatabase 连接不会获得通过 FMDatabaseQueue 插入的信息。