您的位置:首页 > 数据库

关于CoreData和SQLite多线程访问时的线程安全问题

2016-05-20 11:13 495 查看

数据库读取操作一般都是多线程访问的。在对数据进行读取时,我们要保证其当前状态不能被修改,即读取时加锁,否则就会出现数据错误混乱。
IOS中常用的两种数据持久化存储方式:CoreData和SQLite,两者都需要设置线程安全,在这里以FMDB来解释对SQLite的线程安全访问。

一:FMDB的线程安全:(以读取图片为例)

1.没有线程安全的执行方式:

//************** 数据库保存图片  ******************//

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,使用线程队列

//************** 数据库线程安全 ***********//
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创建一个线程队列:

。。。
_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中会锁定当前数据库

dispatch_sync(_queue, ^() {
FMDatabase *db = [self database];
block(db);
……
}

我们可以看到实际上这里是对整个数据库进行加锁,以此来保证线程安全的。

二、CoreData的线程安全

1.没有线程安全的coredata数据读取:

NSManagedObjectContext对象的创建:
_managedObjectContext = [[NSManagedObjectContext alloc] init];


插入数据操作:(AppDetailModal为数据模型)

context 为返回的 _managedObjectContext

AppDetailModal *newapp = [NSEntityDescription insertNewObjectForEntityForName:TableName inManagedObjectContext:context];

其他查询、更新、删除操作
//获取Entity

NSEntityDescription *entity = [NSEntityDescription entityForName:TableName inManagedObjectContext:context];

2.线程安全的coreData操作:

首先创建并行的NSManagedObjectContext对象

NSManagedObjectContext* context=[[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];

然后在执行读取操作时使用一下两个方法:

-(void)performBlock:(void (^)(void))block

-(void)performBlockAndWait:(void (^)(void))block

[context performBlock:^{

//要执行的读取操作

}];


Written with StackEdit.

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: