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

http://www.jianshu.com/p/95db3fc4deb3

关于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.

时间: 2024-08-05 15:18:28

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

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

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

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

设计模式——单例模式(Java)——考虑多线程环境下的线程安全问题

设计模式--单例模式(Java)--考虑多线程环境下的线程安全问题 一:单例模式概念 单例模式是一种常用的软件设计模式.在它的核心结构中只包含一个被称为单例的特殊类.通过单例模式可以保证系统中一个类只有一个实例 二:单例模式的实现方式 特别注意,在多线程环境下,需要对获取对象实例的方法加对象锁(synchronized) 方式一:(懒汉式)程序执行过程中需要这个类的对象,再实例化这个类的对象 步骤: 1.定义静态私有对象 2.构造方法私有化保证在类的外部无法实例化该类的对象 3.定义对外开放的静

android Sqlite多线程访问异常解决方案

在开发Android的程序的时候sqlite数据库是经常用到的:在多线程访问数据库的时候会出现这样的异常:java.lang.IllegalStateException: Cannot perform this operation because the connection pool has been closed.或 java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteData

多线程创建方式及线程安全问题

1.创建线程方式 一:  创建线程方式一继承Thread类 public clsss MyThread extends Thread{ //重写run方法,设置线程任务 Run(){ } } main(){ new MyThread().start(); } 获取线程名称: Thread.currentThread()获取当前线程对象 Thread.currentThread().getName();获取当前线程对象的名称 二:创建线程方式-实现Runnable接口 创建线程的步骤. 1.定义类

多线程(三)-- 线程安全问题

安全解决 -- 互斥锁@synchronized(self) { //开始加锁,操作} 优:解决多线程抢夺资源产生的数据安全问题缺:消耗CPU资源多 使用前提:多条线程执行一块代码时加锁 线程同步:@synchronized()多条线程在同一条线上执行(按顺序执行,与线程并发不同) nonatomic 与 atomicatomic保护线程安全,自动加锁为setter加锁 对比atomic:线程安全,消耗大量资源nonatomic:非线程安全,适合内存小的移动设备

JAVA多线程(一)线程安全问题产生的原因

JAVA线程内存与主存间映射示意图 Java内存模型中规定了所有的变量都存储在主内存中,每条线程还有自己的工作内存,线程的工作内存中保存了该线程使用的变量到主内存副本拷贝,线程对变量的所有操作(读取.赋值)都必须在工作内存中进行,而不能直接读写主内存中的变量.不同线程之间无法直接访问对方工作内存中的变量,线程间变量值的传递均需要在主内存来完成. 工作内存与主内存间交互操作 Java内存模型只保证操作必须按顺序执行,而没有保证必须是连续执行. 以下八种操作来完成 lock(锁定):作用于主内存的变

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

转自原文 C# - 多线程 之 进程与线程 目录 并行~并发 进程~多进程 线程~多线程 线程池 线程同步 线程安全 回到顶部 并行~并发 并发 Concurrency,逻辑上的同时发生,一个处理器(在不同时刻或者说在同一时间间隔内)"同时"处理多个任务.宏观上是并发的,微观上是按排队等待.唤醒.执行的步骤序列执行.并发性是对有限物理资源强制行使多用户共享(多路复用)以提高效率. 并行 Parallelism,物理上的同时发生,多核处理器或多个处理器(在同一时刻)同时处理多个任务.并行

CoreData 与 SQLite 比较

coreData提供ORM(Object Relationships Mapping)解决方案,能直接生成对应的model对象文件,并且封装了一些底层操作,简化了使用,而sqlite要使用c调用对应的api,并进行一些底层的封装操作,且model对象文件要自己写过,代码量会稍大一些,其他感觉差不太多. 后面查了些资料,简单总结下: 首先,coredata和sqlite的概念不同,core为对象周期管理,而sqlite为dbms. 下面的讨论以使用core data来做数据持久化并使用sqlite