sqlite3多线程

前端之家收集整理的这篇文章主要介绍了sqlite3多线程前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。


做iphone项目半年来一直被sqlite3的多线程问题困扰,一直尝试在解决

在项目中,我最开始使用的是sqlite3的activerecord持久化框架sqlite3persistent.framework。但是用于项目中时有以下问题:

1、在多线程查询、保存、修改数据时,经常会有sqlite3的代码执行crash掉(我没有做线程读写锁,并且对锁不熟悉)。

2、不利于大量保存数据。保存大量数据时,执行效率低,影响程序运行

3、若在主线程处理sqlite3,crash机率降低很多,但是会锁死界面。


今天测试了另一个sqlite3的框架fmdb,发现在多线程下表现比sqlite3persistent好很多。就测试而言,未发现在多线程下的crash。

准备更改项目底层数据库代码了。。


为此问题纠结了很久,希望可以帮到有这方面需要的同学,特分享sqlite3多线程代码FMDB代码在github上有,是开源代码点此下载

测试代码如下:

- (void)viewDidLoad {
    [super viewDidLoad];
	opQueue = [[NSOperationQueue alloc] init];
	[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(multiThread1:) userInfo:nil repeats:YES];
	[NSTimer scheduledTimerWithTimeInterval:0.15 target:self selector:@selector(multiThread2:) userInfo:nil repeats:YES];
	[NSTimer scheduledTimerWithTimeInterval:0.17 target:self selector:@selector(multiThread3:) userInfo:nil repeats:YES];
	//[NSTimer scheduledTimerWithTimeInterval:1.3 target:self selector:@selector(multiThread4:) userInfo:nil repeats:NO];
}
- (void) multiThread1:(NSTimer *)timer
{
	NSInvocationOperation * theOp1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(addObject) object:nil];
	[opQueue addOperation:theOp1];
	[theOp1 release];
	//[timer invalidate];
}

- (void) multiThread2:(NSTimer *)timer
{
	NSInvocationOperation * theOp2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(removeObject) object:nil];
	[opQueue addOperation:theOp2];
	[theOp2 release];
}

- (void) multiThread3:(NSTimer *)timer
{
	NSInvocationOperation * theOp3 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(showObject) object:nil];
	[opQueue addOperation:theOp3];
	[theOp3 release];
}


- (void) addObject
{
	NSLog(@"---------------- addObject");
	ContactDao * cdao = [[ContactDao alloc] init];
	Contact * ct = [[Contact alloc] init];
	ct.userid = random();
	ct.friendid = random();
	ct.isrecommend = random()%2;
	ct.isfriend = random()%2;
	NSLog(@"addObject: %d_%d",ct.userid,ct.friendid);
	[cdao saveContact:ct];
	[ct release];
	[cdao release];
}
- (void) removeObject
{
	NSLog(@"---------------- removeObject,count:%D",[list count]);
	ContactDao * cdao = [[ContactDao alloc] init];
	Contact * ct = [cdao findFirstByCriteria:nil];
	NSLog(@"removeObject: %d_%d of index: %d",ct.friendid,ct.index);
	if (ct.index >= 0) {
		[cdao deleteAtIndex:ct.index];
	}
	[cdao release];
}

- (void) showObject
{
	NSLog(@"---------------- showObject,[list count]);
	ContactDao * cdao = [[ContactDao alloc] init];
	Contact * ct = [cdao findFirstByCriteria:nil];
	NSLog(@"showObject: %d_%d",ct.friendid);
	//[cdao deleteAtIndex:ct.index];
	[cdao release];
}

BaseDao类如下:

//
//  BaseDao.h
//  Taonan
//
//  Created by zengconggen on 11-8-30.
//  Copyright 2011 yongmengsoft. All rights reserved.
//

#import <Foundation/Foundation.h>


@class FMDatabase;


@interface BaseDao : NSObject {
	FMDatabase *db;
}


@property (nonatomic,retain) FMDatabase *db;

-(NSString *)sql:(NSString *)sql inTable:(NSString *)table;

@end
//
//  BaseDao.m
//  Taonan
//
//  Created by zengconggen on 11-8-30.
//  Copyright 2011 yongmengsoft. All rights reserved.
//


#import "DB.h"
#import "BaseDao.h"
#import "FMDatabase.h"
#import "FMDatabaseAdditions.h"

#define DB_NAME @"shoujitaonan.db"

@implementation BaseDao

@synthesize db;

- (id)init{
	if(self = [super init])
	{

		BOOL success;
		NSError *error;
		NSFileManager *fm = [NSFileManager defaultManager];
		NSArray  *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
		NSString *documentsDirectory = [paths objectAtIndex:0];
		NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:DB_NAME];
		
		success = [fm fileExistsAtPath:writableDBPath];
		
		if(!success){
			NSString *defaultDBPath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:DB_NAME];
			NSLog(@"%@",defaultDBPath);
			success = [fm copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error];
			if(!success){
				NSLog(@"error: %@",[error localizedDescription]);
			}
			success = YES;
		}
		
		if(success){
			db = [[FMDatabase databaseWithPath:writableDBPath] retain];
			if ([db open]) {
				[db setShouldCacheStatements:YES];
			}else{
				NSLog(@"Failed to open database.");
				success = NO;
			}
		}
	}
	
	return self;
}

-(NSString *)sql:(NSString *)sql inTable:(NSString *)table {
	return [NSString stringWithFormat:sql,table];
}

- (void)dealloc {
	[db close];
	[db release];
	[super dealloc];
}

@end


ContactDao类如下:


//
//  ContactDao.h
//  Taonan
//
//  Created by zengconggen on 11-8-30.
//  Copyright 2011 yongmengsoft. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "BaseDao.h"
#import "Contact.h"

@interface ContactDao : BaseDao {
	
}

- (id) init;

// SELECT
- (NSMutableArray *) findByCriteria:(NSString *)criteria;
- (Contact *) findFirstByCriteria:(NSString *)criteria;
- (NSInteger) countByCriteria:(NSString *)criteria;

// INSERT
- (void) saveContact:(Contact *)contact;
- (void) saveContacts:(NSArray *)contacts;

// UPDATE
- (BOOL) updateAtIndex:(int)index withContact:(Contact *)contact;

// DELETE
- (BOOL) deleteAtIndex:(int)index;


@end

//
//  ContactDao.m
//  Taonan
//
//  Created by zengconggen on 11-8-30.
//  Copyright 2011 yongmengsoft. All rights reserved.
//

#import "Contact.h"
#import "ContactDao.h"
#import "FMDatabase.h"
#import "FMDatabaseAdditions.h"

#define TABLE_NAME @"Contacts"

@implementation ContactDao

- (id) init
{
    if (self = [super init]) {
        //检测是否存在表,不存在则创建
        if (![db tableExists:TABLE_NAME]) {
            NSString * sql = [self sql:@"CREATE TABLE IF NOT EXISTS `%@` (`index` INTEGER PRIMARY KEY AUTOINCREMENT,`userid` INTEGER,`friendid` INTEGER,`isrecommend` smallint,`isfavorite` INTEGER,`isonline` smallint,`isblock` smallint,`isfriend` smallint,`lastlogintime` INTEGER,`lastintouchtime` INTEGER,`distance` INTEGER);" inTable:TABLE_NAME];
            NSLog(@"creating table:%@",sql);
            BOOL result = [db executeUpdate:sql];
			if (result) {
				NSString * sql2 = [self sql:@"CREATE UNIQUE INDEX IF NOT EXISTS `userid_friend` on %@ (`userid`,`friendid`)" inTable:TABLE_NAME];
				[db executeUpdate:sql2];
				NSString * sql3 = [self sql:@"CREATE INDEX IF NOT EXISTS `lastintouchtime` on %@ (`lastintouchtime`)" inTable:TABLE_NAME];
				[db executeUpdate:sql3];
			}
        }
		[db close];
    }
    return self;
}
// SELECT
-(NSMutableArray *)findByCriteria:(NSString *)criteria
{
	NSMutableArray *result = [[[NSMutableArray alloc] initWithCapacity:0] autorelease];
	
    NSMutableString * sql = [NSMutableString stringWithString:[self sql:@"SELECT * FROM %@ " inTable:TABLE_NAME]];
    if (criteria != nil) {
        [sql appendString:criteria];
    }
    
	[db open];
	
	FMResultSet *rs = [db executeQuery:sql];
	while ([rs next]) {
		Contact * ct	= [[Contact alloc] init];
		ct.index			= [rs intForColumn:@"index"];
		ct.userid			= [rs intForColumn:@"userid"];
		ct.friendid			= [rs intForColumn:@"friendid"];
		ct.isrecommend		= [rs intForColumn:@"isrecommend"];
		ct.isfavorite		= [rs intForColumn:@"isfavorite"];
		ct.isonline			= [rs intForColumn:@"isonline"];
		ct.isblock			= [rs intForColumn:@"isblock"];
		ct.isfriend			= [rs intForColumn:@"isfriend"];
		ct.lastlogintime	= [rs intForColumn:@"lastlogintime"];
		ct.lastintouchtime	= [rs intForColumn:@"lastintouchtime"];
		ct.distance			= [rs intForColumn:@"distance"];
		[result addObject:ct];
		[ct release];
	}
	
	[rs close];
	[db close];
	
	return result;
}
// SELECT
-(Contact *)findFirstByCriteria:(NSString *)criteria
{
	NSMutableArray *result = [[[NSMutableArray alloc] initWithCapacity:0] autorelease];
	
    NSMutableString * sql = [NSMutableString stringWithString:[self sql:@"SELECT * FROM %@ " inTable:TABLE_NAME]];
    if (criteria != nil) {
        [sql appendString:criteria];
    }
    [sql appendString:@" limit 1"];
    
	[db open];
	
	FMResultSet *rs = [db executeQuery:sql];
	while ([rs next]) {
		Contact * ct	= [[Contact alloc] init];
		ct.index			= [rs intForColumn:@"index"];
		ct.userid			= [rs intForColumn:@"userid"];
		ct.friendid			= [rs intForColumn:@"friendid"];
		ct.isrecommend		= [rs intForColumn:@"isrecommend"];
		ct.isfavorite		= [rs intForColumn:@"isfavorite"];
		ct.isonline			= [rs intForColumn:@"isonline"];
		ct.isblock			= [rs intForColumn:@"isblock"];
		ct.isfriend			= [rs intForColumn:@"isfriend"];
		ct.lastlogintime	= [rs intForColumn:@"lastlogintime"];
		ct.lastintouchtime	= [rs intForColumn:@"lastintouchtime"];
		ct.distance			= [rs intForColumn:@"distance"];
		[result addObject:ct];
		[ct release];
	}
	
	[rs close];
	
	[db close];
	
    if ([result count] > 0) {
        return [result objectAtIndex:0];
    }else {
        return nil;
    }
}

- (NSInteger) countByCriteria:(NSString *)criteria
{
	NSInteger count = 0;
	
	NSMutableString * sql = [NSMutableString stringWithString:[self sql:@"SELECT COUNT(`index`) AS total FROM %@ " inTable:TABLE_NAME]];
    if (criteria != nil) {
        [sql appendString:criteria];
    }
    
	[db open];
	
	FMResultSet *rs = [db executeQuery:sql];
	while ([rs next]) {
		count			= [rs intForColumn:@"total"];
	}
	
	[db close];
	
	return count;
}

- (void) saveContact:(Contact *)contact
{
    NSInteger index = contact.index;
    
    if (index >= 0) {
        [self updateAtIndex:index withContact:contact];
    }else {
		NSNumber * userid = [[NSNumber alloc] initWithInt:contact.userid];
		NSNumber * friendid = [[NSNumber alloc] initWithInt:contact.friendid];
		NSNumber * isrecommend = [[NSNumber alloc] initWithInt:contact.isrecommend];
		NSNumber * isfavorite = [[NSNumber alloc] initWithInt:contact.isfavorite];
		NSNumber * isonline = [[NSNumber alloc] initWithInt:contact.isonline];
		NSNumber * isblock = [[NSNumber alloc] initWithInt:contact.isblock];
		NSNumber * isfriend = [[NSNumber alloc] initWithInt:contact.isfriend];
		NSNumber * lastlogintime = [[NSNumber alloc] initWithInt:contact.lastlogintime];
		NSNumber * lastintouchtime = [[NSNumber alloc] initWithInt:contact.lastintouchtime];
		NSNumber * distance = [[NSNumber alloc] initWithInt:contact.distance];
		
		[db open];
		
        [db beginTransaction];
        NSString * insertsql = [self sql:@"INSERT OR IGNORE INTO %@ (`userid`,`friendid`,`isrecommend`,`isfavorite`,`isonline`,`isblock`,`isfriend`,`lastlogintime`,`lastintouchtime`,`distance`) VALUES (?,?,?)" inTable:TABLE_NAME];
        [db executeUpdate:insertsql,userid,friendid,isrecommend,isfavorite,isonline,isblock,isfriend,lastlogintime,lastintouchtime,distance];
        NSInteger lastInsertId = [db lastInsertRowId];
        NSString * updatesql = [self sql:@"UPDATE %@ SET userid=?,friendid=?,isrecommend=?,isfavorite=?,isonline=?,isblock=?,isfriend=?,lastlogintime=?,lastintouchtime=?,distance=? WHERE `index`=?" inTable:TABLE_NAME];
        [db executeUpdate:updatesql,distance,[NSNumber numberWithInt:lastInsertId]];
        [db commit];
		
		[db close];
		
		[userid release];
		[friendid release];
		[isrecommend release];
		[isfavorite release];
		[isonline release];
		[isblock release];
		[isfriend release];
		[lastlogintime release];
		[lastintouchtime release];
		[distance release];
    }
}

// INSERT
-(void)saveContacts:(NSArray *)contacts
{
	NSMutableArray * values = [[NSMutableArray alloc] init];
	
	for (Contact * contact in contacts) {
		NSNumber * userid = [[NSNumber alloc] initWithInt:contact.userid];
		NSNumber * friendid = [[NSNumber alloc] initWithInt:contact.friendid];
		NSNumber * isrecommend = [[NSNumber alloc] initWithInt:contact.isrecommend];
		NSNumber * isfavorite = [[NSNumber alloc] initWithInt:contact.isfavorite];
		NSNumber * isonline = [[NSNumber alloc] initWithInt:contact.isonline];
		NSNumber * isblock = [[NSNumber alloc] initWithInt:contact.isblock];
		NSNumber * isfriend = [[NSNumber alloc] initWithInt:contact.isfriend];
		NSNumber * lastlogintime = [[NSNumber alloc] initWithInt:contact.lastlogintime];
		NSNumber * lastintouchtime = [[NSNumber alloc] initWithInt:contact.lastintouchtime];
		NSNumber * distance = [[NSNumber alloc] initWithInt:contact.distance];
		
		NSString * value = [[NSString alloc] initWithFormat:@"(%@,%@,%@)",distance];
		[values addObject:value];
		[value release];
		
		[userid release];
		[friendid release];
		[isrecommend release];
		[isfavorite release];
		[isonline release];
		[isblock release];
		[isfriend release];
		[lastlogintime release];
		[lastintouchtime release];
		[distance release];
	}

	if ([values count] > 0) {
		[db open];
		[db beginTransaction];
		NSString * insertsql = [self sql:@"INSERT OR IGNORE INTO %@ (`userid`,`distance`) VALUES %@" inTable:TABLE_NAME];
		[db executeUpdate:insertsql,[values componentsJoinedByString:@","]];
		[db commit];
		[db close];
	}
	[values release];
}


// UPDATE
-(BOOL)updateAtIndex:(int)index withContact:(Contact *)contact
{
	BOOL success = YES;
	
	NSNumber * indexId = [[NSNumber alloc] initWithInt:index];
	NSNumber * userid = [[NSNumber alloc] initWithInt:contact.userid];
	NSNumber * friendid = [[NSNumber alloc] initWithInt:contact.friendid];
	NSNumber * isrecommend = [[NSNumber alloc] initWithInt:contact.isrecommend];
	NSNumber * isfavorite = [[NSNumber alloc] initWithInt:contact.isfavorite];
	NSNumber * isonline = [[NSNumber alloc] initWithInt:contact.isonline];
	NSNumber * isblock = [[NSNumber alloc] initWithInt:contact.isblock];
	NSNumber * isfriend = [[NSNumber alloc] initWithInt:contact.isfriend];
	NSNumber * lastlogintime = [[NSNumber alloc] initWithInt:contact.lastlogintime];
	NSNumber * lastintouchtime = [[NSNumber alloc] initWithInt:contact.lastintouchtime];
	NSNumber * distance = [[NSNumber alloc] initWithInt:contact.distance];
	
	
	[db open];
	
	[db executeUpdate:[self sql:@"UPDATE %@ SET userid=?,distance=? WHERE `index`=?" inTable:TABLE_NAME],indexId];
	
	[db close];
	
	[indexId release];
	[userid release];
	[friendid release];
	[isrecommend release];
	[isfavorite release];
	[isonline release];
	[isblock release];
	[isfriend release];
	[lastlogintime release];
	[lastintouchtime release];
	[distance release];
	
	if ([db hadError]) {
		NSLog(@"Err %d: %@",[db lastErrorCode],[db lastErrorMessage]);
		success = NO;
	}
	
	return success;
}


// DELETE
- (BOOL)deleteAtIndex:(int)index
{
	BOOL success = YES;
	[db open];
	[db executeUpdate:[self sql:@"DELETE FROM %@ WHERE `index` = ?" inTable:TABLE_NAME],[NSNumber numberWithInt:index]];
	if ([db hadError]) {
		NSLog(@"Err %d: %@",[db lastErrorMessage]);
		success = NO;
	}else {
		[db clearCachedStatements];
	}
	[db close];

	return success;
}



- (void)dealloc
{
	[super dealloc];
}


@end

猜你在找的Sqlite相关文章