现在ios里使用的数据库一般都是Sqlite,但是使用Sqlite有个不太好的地方就是在多线程的时候,会出现问题,sqlite只能打开一个读或者写连结。这样的话多线程就会碰到资源占用的问题。
最开始是使用FMDB,FMDB的早期版本不能解决这个问题,后来FMDB更新了,新版本的FMDB能够很好的解决这个多线程使用Sqlite 。
FMDB github网址 https://github.com/ccgus/fmdb 最新版的请到github取下载。
本文演示了使用FMDB通过多线程来读和写数据库操作。
1.建立数据库表,我采用的是Firefox的Sqlite manager 来建立的。
建表sql如下
CREATE TABLE "tbl_user" ("_id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL , "name" VARCHAR(30), "password" VARCHAR(30))
2. 建立数据表的映射实体UserEntity
#import <Foundation/Foundation.h>
@interface UserEntity : NSObject
{
int _id;
NSString *name;
NSString *password;
}
@property (nonatomic, assign)
int ID;
@property (nonatomic, retain) NSString *name;
@property (nonatomic, retain) NSString *password;
@end
3. 建立操作数据库的dao
//
//
DbDao.m
//
SqliteTest
//
//
Created by foxwang on 12-4-9.
//
Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
//
#import
"
DbDao.h
"
#import
"
DbFileManager.h
"
#import
"
FMDatabase.h
"
#import
"
FMDatabaseAdditions.h
"
#import
"
FMDatabasePool.h
"
#import
"
FMDatabaseQueue.h
"
#import
"
UserEntity.h
"
static DbDao *gSharedInstance = nil;
@implementation DbDao
@synthesize dbFile;
@synthesize dbQueue;
+(DbDao *)sharedInstance
{
@synchronized(self)
{
if (gSharedInstance == nil)
gSharedInstance = [[DbDao alloc] init];
}
return gSharedInstance;
}
- (
void)dealloc
{
[self.dbFile release];
self.dbQueue = nil;
[super dealloc];
}
- (
id)init
{
self = [super init];
if (self)
{
self.dbFile = [DbFileManager dbFilePath];
self.dbQueue = [FMDatabaseQueue databaseQueueWithPath:self.dbFile];
}
return self;
}
- (UserEntity *)rsToUser:(FMResultSet*)rs
{
UserEntity *user = [[[UserEntity alloc] init] autorelease];
user.ID = [rs intForColumn:
@"
_id
"];
user.name = [rs stringForColumn:
@"
name
"];
user.password = [rs stringForColumn:
@"
password
"];
return user;
}
- (
void)addUser:(UserEntity *)user
{
[self.dbQueue inTransaction:^(FMDatabase *db, BOOL *rollback) {
[db open];
NSString *sql =
@"
insert into tbl_user(name, password) values (?, ?)
";
[db executeUpdate:sql,user.name, user.password];
[db close];
}];
}
- (NSArray *)getUsers;
{
__block NSMutableArray *users = [[[NSMutableArray alloc] init] autorelease];
[self.dbQueue inDatabase:^(FMDatabase *db) {
[db open];
NSString *sql =
@"
select * from tbl_user
";
FMResultSet *rs = [db executeQuery:sql];
while ([rs next])
{
[users addObject:[self rsToUser :rs]];
}
[db close];
}];
return users;
}
@end
4. 编写测试方法
在didFinishLaunchingWithOptions 方法里启动3个线程 :2个线程写,1个线程读
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
//
Override point for customization after application launch.
self.viewController = [[[ViewController alloc] initWithNibName:
@"
ViewController
" bundle:nil] autorelease];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
[NSThread detachNewThreadSelector:@selector(writeDbOne) toTarget:self withObject:nil];
[NSThread detachNewThreadSelector:@selector(readDb) toTarget:self withObject:nil];
[NSThread detachNewThreadSelector:@selector(writeDbTwo) 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 addUser: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);
}
}
}
- (
void)readDb
{
DbDao *dao = [DbDao sharedInstance];
NSArray *users = [dao getUsers];
NSLog(
@"
%@
", users);
}
最后查看数据库信息,数据成功插入
结论 :使用新的FMDB ,很好的解决了多线程问题。
项目文件下载
团结就是力量,ios开发者自己的推广联盟 QQ群173063969
|