多线程操作数据库

fmdb使用注意问题:

1、导入:导入库 libsqlite3;

2、多线程操作数据库---FMDatabaseQueue   

  FMResultSet *rs = [db executeQuery:sql,resourceName];
        if ([rs next])
        {
            isHtmlExist = YES;
        }else
        {
            isHtmlExist = NO;
        }
        [rs close];

     FMResultSet 注意结果集的关闭;(单线程操作不关闭,没问题,但是)多线程操作,必须注意,良好的编程习惯很重要;关于 db关闭,写代码的时候没有写,也没报错


3、测试结果

     如果涉及到多线程操作数据库  要点:一个线程FMDatabase操作数据库,同时 多个线程使用FMDatabaseQueue操作数据库是不允许的,必须全部使用FMDatabaseQueue操作,(如果同时写入一张标的话)否则,有些情况,会造成死锁。

    简而言之:项目中,要么只有一个线程操作数据库,只用FMDatabase;要么多线程操作,全部使用FMDatabaseQueue操作(FMDatabaseQueue,这个类的原理,也是把让多个线程的数据库同步排队操作

    测试过程:

     

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // Override point for customization after application launch.
    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];
    
    [NSThread detachNewThreadSelector:@selector(writeDbOne) toTarget:self withObject:nil];
    
    [NSThread detachNewThreadSelector:@selector(writeDbTwo) toTarget:self withObject:nil];
    
    [NSThread detachNewThreadSelector:@selector(readDb) toTarget:self withObject:nil];
    
    return YES;
}



- (void)writeDbOne
{
   DbDao *dao = [DbDao  sharedInstance];
    for (int i = 0; i < 500; i++)
    {
        @autoreleasepool
        {
            UserEntity *user = [[[UserEntity alloc] init] autorelease];
            user.name = [NSString stringWithFormat:@"name %d", i];
            user.password = [NSString stringWithFormat:@"password %d", i];
            [dao addUserInMuliThread:user];
            NSLog(@"writeDbOne %d ", i);
        }
    }
}

- (void)writeDbTwo
{
    DbDao *dao = [DbDao  sharedInstance];
    for (int i = 600; i < 1200; i++)
    {
        @autoreleasepool
        {
            UserEntity *user = [[[UserEntity alloc] init] autorelease];
            user.name = [NSString stringWithFormat:@"name %d", i];
            user.password = [NSString stringWithFormat:@"password %d", i];
            [dao addUser:user];
            NSLog(@"writeDbTwo %d ", i);
        }
    }
}
   一个线程操作fmdbdatabase,一个线程操作FMDBdatabaseQueue,测试结果:

    

2014-08-22 17:28:43.615 FMDBThreadTest[2153:3f03] DB Error: 5 "database is locked"

2014-08-22 17:28:43.617 FMDBThreadTest[2153:3f03] DB Query: select * from tbl_user 

2014-08-22 17:28:43.618 FMDBThreadTest[2153:3f03] DB Path: /Users/pekall_song/Library/Application Support/iPhone Simulator/7.1/Applications/80F58FBE-96B9-4121-94A0-04018877953E/Library/Caches/denghuihua.sqlite

         证明queue采用同步操作的代码:

         

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // Override point for customization after application launch.
    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];
    
    [NSThread detachNewThreadSelector:@selector(writeDbOne) toTarget:self withObject:nil];
    
    [NSThread detachNewThreadSelector:@selector(writeDbTwo) toTarget:self withObject:nil];
    
//    [NSThread detachNewThreadSelector:@selector(readDb) toTarget:self withObject:nil];
    
    return YES;
}



- (void)writeDbOne
{
   DbDao *dao = [DbDao  sharedInstance];
    for (int i = 0; i < 500; i++)
    {
        @autoreleasepool
        {
            UserEntity *user = [[[UserEntity alloc] init] autorelease];
            user.name = [NSString stringWithFormat:@"name %d", i];
            user.password = [NSString stringWithFormat:@"password %d", i];
            [dao addUserInMuliThread:user];
            NSLog(@"writeDbOne %d ", i);
        }
    }
}

- (void)writeDbTwo
{
    DbDao *dao = [DbDao  sharedInstance];
    for (int i = 600; i < 1200; i++)
    {
        @autoreleasepool
        {
            UserEntity *user = [[[UserEntity alloc] init] autorelease];
            user.name = [NSString stringWithFormat:@"name %d", i];
            user.password = [NSString stringWithFormat:@"password %d", i];
            [dao addUserInMuliThread:user];
            NSLog(@"writeDbTwo %d ", i);
        }
    }
}
     

2014-08-22 19:45:17.987 FMDBThreadTest[2449:3507] 同步开始

2014-08-22 19:45:17.989 FMDBThreadTest[2449:3507] *****************sql--name 0--db<FMDatabase: 0x8fa22a0>

2014-08-22 19:45:17.999 FMDBThreadTest[2449:3507] 同步完成

2014-08-22 19:45:18.001 FMDBThreadTest[2449:3507] writeDbOne 0 

2014-08-22 19:45:18.001 FMDBThreadTest[2449:3c03] 同步开始

2014-08-22 19:45:18.004 FMDBThreadTest[2449:3c03] *****************sql--name 600--db<FMDatabase: 0x8fa22a0>

2014-08-22 19:45:18.007 FMDBThreadTest[2449:3c03] 同步完成

2014-08-22 19:45:18.007 FMDBThreadTest[2449:3c03] writeDbTwo 600 

2014-08-22 19:45:18.007 FMDBThreadTest[2449:4103] 同步开始

2014-08-22 19:45:18.086 FMDBThreadTest[2449:4103] 同步完成

2014-08-22 19:45:18.087 FMDBThreadTest[2449:3507] 同步开始

2014-08-22 19:45:18.087 FMDBThreadTest[2449:3507] *****************sql--name 1--db<FMDatabase: 0x8fa22a0>

2014-08-22 19:45:18.089 FMDBThreadTest[2449:3507] 同步完成

2014-08-22 19:45:18.090 FMDBThreadTest[2449:3507] writeDbOne 1 

2014-08-22 19:45:18.090 FMDBThreadTest[2449:3c03] 同步开始

2014-08-22 19:45:18.091 FMDBThreadTest[2449:3c03] *****************sql--name 601--db<FMDatabase: 0x8fa22a0>

2014-08-22 19:45:18.093 FMDBThreadTest[2449:3c03] 同步完成

2014-08-22 19:45:18.097 FMDBThreadTest[2449:3c03] writeDbTwo 601 

2014-08-22 19:45:18.097 FMDBThreadTest[2449:3507] 同步开始

2014-08-22 19:45:18.099 FMDBThreadTest[2449:3507] *****************sql--name 2--db<FMDatabase: 0x8fa22a0>

2014-08-22 19:45:18.101 FMDBThreadTest[2449:3507] 同步完成

2014-08-22 19:45:18.102 FMDBThreadTest[2449:3507] writeDbOne 2 

2014-08-22 19:45:18.103 FMDBThreadTest[2449:3c03] 同步开始

2014-08-22 19:45:18.103 FMDBThreadTest[2449:3c03] *****************sql--name 602--db<FMDatabase: 0x8fa22a0>

2014-08-22 19:45:18.105 FMDBThreadTest[2449:3c03] 同步完成

   由打印结果可知,在一个数据库操作没有执行之前,另外一个数据库操作是不会执行的。                            

4、不重要,但是也不太确定的经验

   每个线程分别操作自己的FMDatabase对象-----会导致数据库死锁

    两个线程操作一个FMDatabase对象--in use 

     一个线程操作多个FMDatabase对象--(不科学)但是平常使用都用单例对象 ---估计是出于内存原因考虑

  

   补充关于操作队列的认识:

    根据cpu繁忙程度,自己分配线程,相同代码任务,不一定是同一个线程;

   切记,也就是说如果操作到共有资源,注意只用同步锁;否则报些数据库 busy  ,ID not 唯一的错,也是很烦人的。。。。


5、下面的情况需要使用同步锁

      

-(void)downAndWritePictureToLocalWithUrl:(NSString *)url
{
    [self.lock lock];
   NSString *imageName = [[[[url componentsSeparatedByString:@"/"] lastObject] componentsSeparatedByString:@"?"] firstObject];
    if ([NDTResouceVerificationHelper shouldDownResourceInSubThread:imageName])
    {
        NSURL *downImageURL = [NSURL URLWithString:url];
        NSError *error;
        NSData *imageData = [NSData dataWithContentsOfURL:downImageURL options:NSDataReadingUncached error:&error];
        if (error)
        {
            [self performSelectorOnMainThread:@selector(showAlert:) withObject:url waitUntilDone:YES];
        }else
        {
            
            UIImage *image = [[UIImage alloc] initWithData:imageData];
            [UIImageJPEGRepresentation(image, 1.0) writeToFile:[self getImagePath:imageName] atomically:YES];
            
                //文件名称写入数据库
                NDTResouceModel *resourceItem = [[NDTResouceModel alloc] init];
                resourceItem.resouceID = url;
                resourceItem.resouceName = imageName;
                [[NDDatabase sharedDatabase] insertResourceItemInMultipleThread :resourceItem];
        }
    }
    [self.lock unlock];
}
     上述代码中,downAndWritePictureToLocalWithUrl方法,在分线程中执行且有多个对象实例调用该方法,虽然2步数据库操作都在队列中执行,但是不能确定哪一步先放入队列,所以还是需要使用同步锁

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值