使用FMDB多线程访问数据库,及database is locked的问题
来源:互联网 发布:nba2k17吴亦凡捏脸数据 编辑:程序博客网 时间:2024/04/23 21:32
每日更新关注:http://weibo.com/hanjunqiang 新浪微博
今天终于解决了多线程同时访问数据库时,报数据库锁定的问题,错误信息是:
Unknown error finalizing or resetting statement (5: database is locked)
最后通过FMDatabaseQueue解决了这个问题,本文总结一下:
FMDatabase不能多线程使用同一个实例
多线程访问数据库,不能使用同一个FMDatabase的实例,否则会发生异常。如果线程使用单独的FMDatabase实例是允许的,但是同样有可能发生database is locked的问题。这是由于多线程对sqlite的竞争引起的
我的app一开始就是多线程使用单独的FMDatabase实例访问数据库,虽然没有引起crash,但是还是出现了database is locked问题,造成很多数据没有如预期写入数据库
使用FMDatabaseQueue,问题依旧
后来上FMDB的官网看了文档,确认用FMDatabaseQueue可以解决这个问题,API也比较简单:
NSString *dbFilePath = [PathResolver databaseFilePath];queue = [FMDatabaseQueue databaseQueueWithPath:dbFilePath];[queue inDatabase:^(FMDatabase *db){ // access db}];每日更新关注:http://weibo.com/hanjunqiang 新浪微博
但是实际测试了一下,还是database is locked
读了一下相关的源码,FMDatabaseQueue解决这个问题的思路是:创建一个队列,然后将放入队列的block顺序执行,这样避免了多线程同时访问数据库
而我的代码是多线程各创建FMDatabaseQueue的实例,所以其实有多个队列,因此还是存在数据库竞争的问题,和用FMDatabase时是一样的
共享同一个FMDatabaseQueue实例
于是接下来我让每个线程使用同一个Queue实例,问题就顺利解决了
实现的方式,一开始我想给FMDatabase增加一个单例方法,但是这样以后升级FMDB会比较麻烦,所以最后我是创建了一个Helper类
@implementation LosDatabaseHelper{ FMDatabaseQueue* queue;}-(id) init{ self = [super init]; if(self){ NSString *dbFilePath = [PathResolver databaseFilePath]; queue = [FMDatabaseQueue databaseQueueWithPath:dbFilePath]; } return self;}+(LosDatabaseHelper*) sharedInstance{ static dispatch_once_t pred = 0; __strong static id _sharedObject = nil; dispatch_once(&pred, ^{ _sharedObject = [[self alloc] init]; }); return _sharedObject;}-(void) inDatabase:(void(^)(FMDatabase*))block{ [queue inDatabase:^(FMDatabase *db){ block(db); }];}@end
每日更新关注:http://weibo.com/hanjunqiang 新浪微博
使用FMDatabaseQueue之后,管理db
原本使用FMDatabase类,需要手工调用db的open和close方法
但是用FMDatabaseQueue,不需要调用open,因为查看代码发现,Queue已经open了。至于要不要close,我也不确定,因 为官方的sample code没有调用close。实际应用中,我也没有调用,好像没有问题。如果需要close的话,我想可以在Helper类的公共方法里增加调用 close queue就可以了。下面是close的源码:
- (void)close { FMDBRetain(self); dispatch_sync(_queue, ^() { [_db close]; FMDBRelease(_db); _db = 0x00; }); FMDBRelease(self);}
if ([db hasOpenResultSets]) { NSLog(@"Warning: there is at least one open result set around after performing [FMDatabaseQueue inDatabase:]");
刷新数据库文件路径
具体到我们的应用,还有一个特殊问题需要考虑。因为我们的APP可以切换账户,而账户的db文件是独立的。所以当用户重新登录的时候,需要刷新一下Helper的queue
+(void) refreshDatabaseFile{ LosDatabaseHelper *instance = [self sharedInstance]; [instance doRefresh];}-(void) doRefresh{ NSString *dbFilePath = [PathResolver databaseFilePath]; queue = [FMDatabaseQueue databaseQueueWithPath:dbFilePath];}
队列和线程
在debug过程中,顺便看到一个现象。虽然多个block都是放到同一个队列里,但是其实是跑在不同的thread里
每日更新关注:http://weibo.com/hanjunqiang 新浪微博
- 使用FMDB多线程访问数据库,及database is locked的问题
- 使用FMDB多线程访问数据库,及database is locked的问题
- FMDB多线程访问数据库,database is locked的问题
- ios FMDB多线程"is currently in use", "database is locked"问题的解决
- 使用FMDB多线程访问数据库 及databaseislocked的问题
- FMDB中出现的database is locked
- FMDB多线程下"is currently in use" 或者 "database is locked" 问题
- FMDB多线程下"is currently in use" 或者 "database is locked" 问题
- FMDB多线程下"is currently in use" 或者 "database is locked" 问题
- delphi中使用sqlite数据库出现database is locked问题
- FMDB多线程下"is currently in use" 或者 "database is locked" 已解决!
- sqlite遇到database is locked问题的完美解决
- sqlite遇到database is locked问题的完美解决
- sqlite遇到database is locked问题的完美解决
- sqlite遇到database is locked问题的完美解决
- sqlite遇到database is locked问题的完美解决方案
- sqlite遇到database is locked问题的完美解决
- SQLite并发操作下的分析与处理,解决database is locked,以及多线程下执行事务等问题
- Bootstrap、jQuery、HTML5、Spring Security安全权限
- 4027: [HEOI2015]兔子与樱花 贪心
- Concurrency5
- 剩菜到底能不能吃?浙江大学实验室给你最权威的答案
- SQL Server外连接、内连接、交叉连接
- 使用FMDB多线程访问数据库,及database is locked的问题
- 分析和解决JAVA 内存泄露的实战例子
- DEDE 网站后台被黑链修改了,自己登入不上去,怎么办?
- Error page: /admin/makehtml_all.php?action=make&step怎么办
- R-ggplot 数据可视化
- assertThat用法
- DEDE如何修改后台目录?
- DEDE怎么取消后台验证码
- 设计模式——装饰者模式 Java源代码