关于CoreData和SQLite多线程访问时的线程安全问题
数据库读取操作一般都是多线程访问的。在对数据进行读取时,我们要保证其当前状态不能被修改,即读取时加锁,否则就会出现数据错误混乱。
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.
关于CoreData和SQLite多线程访问时的线程安全问题的更多相关文章
- CoreData和SQLite多线程访问时的线程安全问题
数据库读取操作一般都是多线程访问的.在对数据进行读取时,我们要保证其当前状态不能被修改,即读取时加锁,否则就会出现数据错误混乱.IOS中常用的两种数据持久化存储方式:CoreData和SQLite,两 ...
- CoreData和SQLite多线程访问时的线程安全
关于CoreData和SQLite多线程访问时的线程安全问题 数据库读取操作一般都是多线程访问的.在对数据进行读取时,我们要保证其当前状态不能被修改,即读取时加锁,否则就会出现数据错误混乱.IOS中常 ...
- redis是单进程数据库,多用户排队对统一数据进行访问,不存在并发访问生产的线程安全问题
redis是单进程数据库,多用户排队对统一数据进行访问,不存在并发访问生产的线程安全问题. oracle是多进程数据库,存在并发访问的问题,必须事务加锁等方式进行处理.
- (原创)android Sqlite多线程访问异常解决方案
在开发Android的程序的时候sqlite数据库是经常用到的:在多线程访问数据库的时候会出现这样的异常:java.lang.IllegalStateException: Cannot perform ...
- C# - 多线程 之 进程与线程
并行~并发 并发 Concurrency,逻辑上的同时发生,一个处理器(在不同时刻或者说在同一时间间隔内)"同时"处理多个任务.宏观上是并发的,微观上是按排队等待.唤醒.执行的步骤 ...
- IOS 使用FMDB多线程访问数据库 及databaseislocked的问题
原理:文件数据库sqlite,同一时刻允许多个进程/线程读,但同一时刻只允许一个线程写.在操行写操作时,数据库文件被琐定,此时任何其他读/写操作都被阻塞,如果阻塞超过5秒钟(默认是5秒,能过重新编译s ...
- SQLite多线程写锁文件解决方案
在sqlite编程中多线程同时写时会出现异常,我写了个类来解决这个问题. 思路很简单,就是在开始写操作时,记下写操作的托管线程id,表示目前有线程正在做写操作:其他线程来写时,需要先检测是否有进程正在 ...
- 使用FMDB多线程访问数据库,及database is locked的问题
每日更新关注:http://weibo.com/hanjunqiang 新浪微博 今天终于解决了多线程同时访问数据库时,报数据库锁定的问题,错误信息是: Unknown error finalizi ...
- Sqlite多线程相关整理
Sqlite多线程相关整理 Sqlite With MultiThreads 什么是线程安全? 当多个线程访问某个方法时,不管你通过怎样的调用方式.或者说这些线程如何交替地执行,我们在主程序中不需要去 ...
随机推荐
- 1934. Black Spot(spfa)
1934 水题 RE了N久 后来发现是无向图 #include <iostream> #include<cstring> #include<algorithm> # ...
- uva live 6170
Esspe-Peasee Esspe-Peasee is an ancient game played by children throughout the land of Acmania. The ...
- Qt之自定义界面(窗体缩放-跨平台终极版)
简述 通过上一节内容,我们实现了窗体的缩放,功能很不错,但是很遗憾-不支持跨平台!如果对于多平台来说,这是一个硬伤,所以,我们急需要一个能够支持跨平台的实现方案. 在网上看到过很多不同的实现方式,多多 ...
- TYVJ 1066 合并果子【优先队列】
题意:给出n堆果子,需要将n堆果子合并成一堆,问将所有堆的果子合成一堆所需要花费的最少的力气 因为要使耗费力气最小,即需要每次搬动的那堆重量小,所以可以选取两堆最轻的合并,合并之后再插入还没有合并的堆 ...
- EF4.0和EF5.0增删改查的写法区别及执行Sql的方法
EF4.0和EF5.0增删改查的写法区别 public T AddEntity(T entity) { //EF4.0的写法 添加实体 //db.CreateObjectSet<T>(). ...
- js学习总结
转自 http://blog.sina.com.cn/s/blog_75cf5f3201011csu.html 一: 关于基本数据类型在栈内存和堆内存中的关系 基本数据对于栈内存和堆内存是可以复制的, ...
- POJ 1664 放苹果
放苹果 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 24985 Accepted: 15908 Description ...
- zoj 1967 Fiber Network/poj 2570
题意就是 给你 n个点 m条边 每条边有些公司支持 问 a点到b点的路径有哪些公司可以支持 这里是一条路径中要每段路上都要有该公司支持 才算合格的一个公司// floyd 加 位运算// 将每个字符当 ...
- 【转】android:layout_gravity和android:gravity的区别
1.首先来看看android:layout_gravity和android:gravity的使用区别. android:gravity: 这个是针对控件里的元素来说的,用来控制元素在该控件里的显示位置 ...
- C#中使用visio控件
C#中使用visio控件 2012-08-25 18:14:19| 分类: 技术相关|举报|字号 订阅 其实就是C#访问VISIO的自动化模型,以前做了不少C#和Excle及word 的交互 ...