ios FMDB多线程"is currently in use", "database is locked"问题的解决

骑猪看日落 2022-06-08 07:44 306阅读 0赞

is currently in use” 出现的场景是这样的,多线程操作数据库,每个线程都使用了FMDatabase实例

FMDatabase是不具备线程安全的,如果两个线程中同时操作数据库,就会”is currently in use” ;FMDatabasequeue其实是一个调度队列(G-C-D),数据库的操作必须是顺序执行,不能两个数据库的操作同时执行,如果是两个线程各自创建了FMDatabaseQueue的实例,线程同时执行时,就会出现相同的数据库操作同时触发,导致”database is locked“,所以必须是一个FMDatabaseQueue实例下,多个线程下同时操作,其实是在排在同一个队列中逐一操作的,没有同时操作。

解决办法:

自定义一个 DatabaseHelper类

DatabaseHelper.h

  1. #import <Foundation/Foundation.h>
  2. #import "FMDB.h"
  3. @interface DatabaseHelper : NSObject
  4. @property(nonatomic,strong)NSString *dbName;
  5. +(DatabaseHelper*) sharedInstance;
  6. -(void)inDatabase:(void(^)(FMDatabase*))block;
  7. - (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block;
  8. - (void)close;
  9. @end

DatabaseHelper.m

  1. #import "DatabaseHelper.h"
  2. @interface DatabaseHelper()
  3. @property(nonatomic,strong)NSString *dbPath;
  4. @end
  5. @implementation DatabaseHelper
  6. {
  7. FMDatabaseQueue* queue;
  8. }
  9. -(NSString *)dbPath {
  10. if (!_dbPath) {
  11. _dbPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject] stringByAppendingPathComponent:@"datas.db"];
  12. NSLog(@"%@",_dbPath);
  13. }
  14. return _dbPath;
  15. }
  16. -(id) init
  17. {
  18. self = [super init];
  19. if(self){
  20. //NSString *dbFilePath = [PathResolver databaseFilePath];
  21. queue = [FMDatabaseQueue databaseQueueWithPath:self.dbPath];
  22. }
  23. return self;
  24. }
  25. +(DatabaseHelper*)sharedInstance
  26. {
  27. static dispatch_once_t pred = 0;
  28. __strong static id _sharedObject = nil;
  29. dispatch_once(&pred, ^{
  30. _sharedObject = [[self alloc] init];
  31. });
  32. return _sharedObject;
  33. }
  34. -(void)inDatabase:(void(^)(FMDatabase*))block
  35. {
  36. [queue inDatabase:^(FMDatabase *db){
  37. block(db);
  38. }];
  39. }
  40. - (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block {
  41. [queue inTransaction:^(FMDatabase *db, BOOL *rollback) {
  42. block(db,rollback);
  43. }];
  44. }
  45. - (void)close {
  46. [queue close];
  47. }
  48. @end

案例:

  1. #import "ViewController.h"
  2. #import "DatabaseHelper.h"
  3. @interface ViewController ()
  4. @property(nonatomic,strong)DatabaseHelper *dbQueue;
  5. @end
  6. @implementation ViewController
  7. -(DatabaseHelper *)dbQueue {
  8. if (!_dbQueue) {
  9. _dbQueue = [DatabaseHelper sharedInstance];//单例
  10. }
  11. return _dbQueue;
  12. }
  13. - (void)viewDidLoad {
  14. [super viewDidLoad];
  15. dispatch_queue_t q1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
  16. for (int i=0; i<1000; i++) {
  17. dispatch_async(q1, ^{
  18. [self.dbQueue inTransaction:^(FMDatabase *db, BOOL *rollback) {
  19. BOOL isSucess = [db executeUpdate:@"create table if not exists test(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, nameTwo TEXT)"];
  20. BOOL isSucess2 = [db executeUpdate:@"insert into test(name) values('YKJ')"];
  21. BOOL isSucess3 = [db executeUpdate:@"insert into test(nameTwo) values('ZJT')"];
  22. BOOL isSucess4 = [db executeUpdate:@"UPDATE test SET name = 'ting'"];
  23. BOOL isSucess5 = [db executeUpdate:@"UPDATE test SET nameTwo = 'tingJin'"];
  24. if (!isSucess || isSucess2 || isSucess3 || isSucess4 || isSucess5) {
  25. *rollback = YES;//回滚
  26. return;
  27. }
  28. }];
  29. });
  30. }
  31. }
  32. @end

我的业余技术微信公众号:YKJGZH,欢迎大家进入

发表评论

表情:
评论列表 (有 0 条评论,306人围观)

还没有评论,来说两句吧...

相关阅读