数据库读取操作一般都是多线程访问的。在对数据进行读取时,我们要保证其当前状态不能被修改,即读取时加锁,否则就会出现数据错误混乱。
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多线程访问时的线程安全问题的更多相关文章

  1. CoreData和SQLite多线程访问时的线程安全问题

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

  2. CoreData和SQLite多线程访问时的线程安全

    关于CoreData和SQLite多线程访问时的线程安全问题 数据库读取操作一般都是多线程访问的.在对数据进行读取时,我们要保证其当前状态不能被修改,即读取时加锁,否则就会出现数据错误混乱.IOS中常 ...

  3. redis是单进程数据库,多用户排队对统一数据进行访问,不存在并发访问生产的线程安全问题

    redis是单进程数据库,多用户排队对统一数据进行访问,不存在并发访问生产的线程安全问题. oracle是多进程数据库,存在并发访问的问题,必须事务加锁等方式进行处理.

  4. (原创)android Sqlite多线程访问异常解决方案

    在开发Android的程序的时候sqlite数据库是经常用到的:在多线程访问数据库的时候会出现这样的异常:java.lang.IllegalStateException: Cannot perform ...

  5. C# - 多线程 之 进程与线程

    并行~并发 并发 Concurrency,逻辑上的同时发生,一个处理器(在不同时刻或者说在同一时间间隔内)"同时"处理多个任务.宏观上是并发的,微观上是按排队等待.唤醒.执行的步骤 ...

  6. IOS 使用FMDB多线程访问数据库 及databaseislocked的问题

    原理:文件数据库sqlite,同一时刻允许多个进程/线程读,但同一时刻只允许一个线程写.在操行写操作时,数据库文件被琐定,此时任何其他读/写操作都被阻塞,如果阻塞超过5秒钟(默认是5秒,能过重新编译s ...

  7. SQLite多线程写锁文件解决方案

    在sqlite编程中多线程同时写时会出现异常,我写了个类来解决这个问题. 思路很简单,就是在开始写操作时,记下写操作的托管线程id,表示目前有线程正在做写操作:其他线程来写时,需要先检测是否有进程正在 ...

  8. 使用FMDB多线程访问数据库,及database is locked的问题

    每日更新关注:http://weibo.com/hanjunqiang  新浪微博 今天终于解决了多线程同时访问数据库时,报数据库锁定的问题,错误信息是: Unknown error finalizi ...

  9. Sqlite多线程相关整理

    Sqlite多线程相关整理 Sqlite With MultiThreads 什么是线程安全? 当多个线程访问某个方法时,不管你通过怎样的调用方式.或者说这些线程如何交替地执行,我们在主程序中不需要去 ...

随机推荐

  1. 1934. Black Spot(spfa)

    1934 水题 RE了N久 后来发现是无向图 #include <iostream> #include<cstring> #include<algorithm> # ...

  2. uva live 6170

    Esspe-Peasee Esspe-Peasee is an ancient game played by children throughout the land of Acmania. The ...

  3. Qt之自定义界面(窗体缩放-跨平台终极版)

    简述 通过上一节内容,我们实现了窗体的缩放,功能很不错,但是很遗憾-不支持跨平台!如果对于多平台来说,这是一个硬伤,所以,我们急需要一个能够支持跨平台的实现方案. 在网上看到过很多不同的实现方式,多多 ...

  4. TYVJ 1066 合并果子【优先队列】

    题意:给出n堆果子,需要将n堆果子合并成一堆,问将所有堆的果子合成一堆所需要花费的最少的力气 因为要使耗费力气最小,即需要每次搬动的那堆重量小,所以可以选取两堆最轻的合并,合并之后再插入还没有合并的堆 ...

  5. EF4.0和EF5.0增删改查的写法区别及执行Sql的方法

    EF4.0和EF5.0增删改查的写法区别 public T AddEntity(T entity) { //EF4.0的写法 添加实体 //db.CreateObjectSet<T>(). ...

  6. js学习总结

    转自 http://blog.sina.com.cn/s/blog_75cf5f3201011csu.html 一: 关于基本数据类型在栈内存和堆内存中的关系 基本数据对于栈内存和堆内存是可以复制的, ...

  7. POJ 1664 放苹果

    放苹果 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 24985   Accepted: 15908 Description ...

  8. zoj 1967 Fiber Network/poj 2570

    题意就是 给你 n个点 m条边 每条边有些公司支持 问 a点到b点的路径有哪些公司可以支持 这里是一条路径中要每段路上都要有该公司支持 才算合格的一个公司// floyd 加 位运算// 将每个字符当 ...

  9. 【转】android:layout_gravity和android:gravity的区别

    1.首先来看看android:layout_gravity和android:gravity的使用区别. android:gravity: 这个是针对控件里的元素来说的,用来控制元素在该控件里的显示位置 ...

  10. C#中使用visio控件

    C#中使用visio控件 2012-08-25 18:14:19|  分类: 技术相关|举报|字号 订阅     其实就是C#访问VISIO的自动化模型,以前做了不少C#和Excle及word 的交互 ...