CoreData和SQLite多线程访问时的线程安全问题
數據庫讀取操作一般都是多線程訪問的。在對數據進行讀取時,我們要保證其當前狀態不能被修改,即讀取時加鎖,否則就會出現數據錯誤混亂。
IOS中常用的兩種數據持久化存儲方式:CoreData和SQLite,兩者都需要設置線程安全,在這里以FMDB來解釋對SQLite的線程安全訪問。
?
一:FMDB的線程安全:(以讀取圖片為例)
1.沒有線程安全的執行方式:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | //************** 數據庫保存圖片? ******************// ?FMDatabase *database = [FMDatabase databaseWithPath:[self?getDatabasePath]]; ?//打開數據庫 ?[database open]; ?NSString?*sql = @"create table if not exists Test (id integer primary key autoincrement,name text,image blob);"; ?//創建表 ?[database executeUpdate:sql]; ?//把UIImage對象轉化為NSData ?NSData?*data = UIImagePNGRepresentation([UIImage imageNamed:@"user_browse"]);??? ?//寫入數據 ?sql = @"insert into Test (name,image) values (?,?)"; ?[database executeUpdate:sql,@"張三",data]; ?//讀取顯示 ?sql = @"select * from Test;"; ?FMResultSet *resultSet = [database executeQuery:sql]; ?while?(resultSet.next) ?{ ?????//[resultSet dataForColumn:@"image"]; ?????NSData?*imageData = [resultSet dataForColumnIndex:2]; ?????UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 300, 300)]; ?????imageView.image = [UIImage imageWithData:imageData]; ?????[self.view addSubview:imageView]; ?} |
2,使用線程隊列
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | //************** 數據庫線程安全 ***********// ????FMDatabaseQueue *queue = [[FMDatabaseQueue alloc] initWithPath:[self?getDatabasePath]]; ????[queue inDatabase:^(FMDatabase *db) { ????????//線程安全的 ????????__block?NSString?*sql = @"create table if not exists Test (id integer primary key autoincrement,name text,image blob);"; ????????//創建表 ????????[database executeUpdate:sql]; ????}]; ????//插入數據 ????[queue inDatabase:^(FMDatabase *db) { ????????//寫入數據 ????????sql = @"insert into Test (name,image) values (?,?)"; ????????[database executeUpdate:sql,@"張三",data]; ????}]; ????//讀取 ????[queue inDatabase:^(FMDatabase *db) { ????????//讀取顯示 ????????sql = @"select * from Test;"; ????????FMResultSet *resultSet = [database executeQuery:sql]; ????????while?(resultSet.next) ????????{ ????????????//[resultSet dataForColumn:@"image"]; ????????????NSData?*imageData = [resultSet dataForColumnIndex:2]; ????????????UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 300, 300)]; ????????????imageView.image = [UIImage imageWithData:imageData]; ????????????[self.view addSubview:imageView]; ????????} ????}]; |
分析一下線程安全下的FMDB的實現:
在當使用FMDBDatabaseQueue創建數據庫時,會使用GCD創建一個線程隊列:
| 1 2 3 4 5 | 。。。 ?_queue = dispatch_queue_create([[NSString?stringWithFormat:@"fmdb.%@",?self] UTF8String],?NULL); ????????dispatch_queue_set_specific(_queue, kDispatchQueueSpecificKey, (__bridge?void?*)self,?NULL); ????????_openFlags = openFlags; 。。。 |
然后在讀取時調用[queue inDatabase:^(FMDatabase *db)方法,在block中會鎖定當前數據庫
| 1 2 3 4 5 | dispatch_sync(_queue, ^() { ????????FMDatabase *db = [self?database]; ????????block(db); ????…… } |
我們可以看到實際上這里是對整個數據庫進行加鎖,以此來保證線程安全的。
?
二、CoreData的線程安全
1.沒有線程安全的coredata數據讀取:
NSManagedObjectContext對象的創建:_managedObjectContext = [[NSManagedObjectContext alloc] init];
插入數據操作:(AppDetailModal為數據模型)
context 為返回的 _managedObjectContext
| 1 | AppDetailModal *newapp = [NSEntityDescription?insertNewObjectForEntityForName:TableName inManagedObjectContext:context]; |
其他查詢、更新、刪除操作
//獲取Entity
| 1 | NSEntityDescription?*entity = [NSEntityDescription?entityForName:TableName inManagedObjectContext:context]; |
2.線程安全的coreData操作:
首先創建并行的NSManagedObjectContext對象
| 1 | NSManagedObjectContext* context=[[NSManagedObjectContext?alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; |
| 1 2 3 4 5 | 然后在執行讀取操作時使用一下兩個方法: -(void)performBlock:(void?(^)(void))block -(void)performBlockAndWait:(void?(^)(void))block |
| 1 2 3 4 5 | [context performBlock:^{ ????????//要執行的讀取操作 ?}]; |
轉載于:https://www.cnblogs.com/graveliang/p/5818696.html
總結
以上是生活随笔為你收集整理的CoreData和SQLite多线程访问时的线程安全问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: a链接的四个伪类顺序
- 下一篇: 相关子查询 与非相关子查询