FMDatabase用于所有READ查询和
所有UPDATE查询的FMDatabaseQueue.
两者都由单例处理,它在应用程序运行时保持两种类型的打开.
读取和更新查询都在不同的线程中使用,因为我的应用程序中的某些任务在后台进行;例如从服务器获取数据,并通过FMDatabaseQueue将其插入到自己的后台线程中,同时通过FMDatabase从db读取一些信息,并在主线程上更新VIEwController.
我的问题是,通过FMDatabaseQueue将数据插入数据库后,第二个连接(FMDatabase)不会返回更新的信息,因为它们没有找到它们.但是我知道数据被插入,因为我已经用db浏览器工具检查了db,而插入它没有错误.为了避免这种情况,我必须关闭FMDatabase数据库连接并重新打开它以查看其他连接所做的更改.不幸的是,当我的应用程序启动时,有许多插入,更新读取,因为大量的新数据从需要处理的服务器加载 – 因此,每当更新发生时,在许多“数据库繁忙”消息中关闭和打开数据库.
我已经为所有线程使用了一个单一的FMDatabaseQueue,然后执行(读取和更新),但是当使用带有__block变量的读取查询将结果集从回调中取出时相当慢,而另一个线程执行一些插入(在50-100之间)单笔交易).
在它的顶部,数据库通过sqlcipher加密 – 不知道如果它是重要的,但想提到它.所以每次我必须关闭并打开数据库,我正在做一个setKey.
我的问题:是否可以在多个线程上使用具有两种不同连接类型的设置,如果是,是否必须关闭并打开FMDatabase连接?还是有更好的解决方案?
UPDATE
我的代码执行插入/更新看起来像
-(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插入的信息.
解决方法 就个人而言,我建议为两个线程使用单个FMDatabaseQueue
,并让队列协调两个线程上的动作.这就是为它创造的.它完全消除了这些“数据库忙”问题. 在性能更新中,如果进行批量更新,则在更新之前是否使用FMDatabase方法beginTransaction
,最后使用commit
?或使用inTransaction方法.在我的测试中插入10,000条记录没有交易需要36.8秒,但是事务需要0.25秒.
或者,如果您的批量更新是必要的缓慢(例如,您使用某种流式协议从Web服务下载某些大数据源),您可以:
>首先将所有结果加载到内存中,没有数据库交互,然后使用上一段所述的交易的批量更新;要么
>如果您的数据库更新必然受到较慢的网络连接的约束,则使用单独的inDatabase调用,以便在从Web服务下载数据时不会调出FMDatabaseQueue.
底线,通过使用事务或明智地使用单独的inDatabase调用,可以最大限度地减少后台 *** 作涉及FMDatabaseQueue的时间,并且可以实现与数据库的同步多线程交互,而不会太大地阻止用户界面.
总结以上是内存溢出为你收集整理的ios – 在多个线程和两个连接上使用FMDB全部内容,希望文章能够帮你解决ios – 在多个线程和两个连接上使用FMDB所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)