sqlite在移動客戶端的開發非常常見,我之前做過一個ios項目中也用到,無耐技術水平有限,做的不是很好!但是一查網上這方面的總結不是很多,可能大牛們都忙着賺錢去了,我就獻醜將我在項目中用到的東西貢獻出來,有什麼不好的地方請指教。值得說明的是我是看了某個網站貼出的demo而稍作改進,若此君不小心看到本篇小作,請指出,如有需要可以刪除此文。下面開始介紹我的做的東西:
1.用到主要的函數有sqlite3_open,sqlite3_close,sqlite3_exe這裏我不解釋這些函數的用法了(http://www.cppblog.com/woaidongmao/archive/2009/06/23/88361.html,有詳細介紹),直接進入正題。
2.這個例子裏面涉及如下幾個文件,DatabaseConnection,DatabaseStatement,DataBaseCenter.在這個demo中我只要用到一個數據庫
DatabaseConnection.h
#import <Foundation/Foundation.h>
#import "sqlite3.h"
#import "DataStatement.h"
@interface DataConnection : NSObject
//建表
+(void)exeCreate:(NSString*)createString;
+(sqlite3*)sharedDataBase; //訪問單例
+(void)closeDataBase; //關閉數據庫連接,置空句柄
+(void)beginTransaction; //開始事務
+(void)commitTransaction; //提交事務
+ (DataStatement*)statementWithQuery:(const char*)sql; //初始化一個連接
+(void)alert; //提出警告
+(int)getRowsWithQury:(const char*)sql; //獲取select語句中結果數據的行數
@end
DatabaseConnection.m
#import "DataConnection.h"
#define DATABASENAME @"Demo.db"
static sqlite3 *dataBaseInstance = nil;
@implementation DataConnection
+(void)exeCreate:(NSString*)createString
{
char *errorMsg;
if (sqlite3_exec(dataBaseInstance, [createString UTF8String], NULL, NULL, &errorMsg)!=SQLITE_OK)
{
NSAssert1(0, @"can not create users table,'%s'.",errorMsg);
}
[self closeDataBase];
}
+(sqlite3*)openDataBase:(NSString*)dataBaseName
{
NSArray *array = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString * path = [array objectAtIndex:0];
NSString * databasePath = [path stringByAppendingPathComponent:dataBaseName];
if (sqlite3_open([databasePath UTF8String], &dataBaseInstance)!=SQLITE_OK)
{
NSLog(@"can not open the database:%@",sqlite3_errmsg(dataBaseInstance));
sqlite3_close(dataBaseInstance);
return nil;
}
return dataBaseInstance;
}
+(sqlite3*)sharedDataBase
{
if (nil == dataBaseInstance) {
@synchronized(self)
{
dataBaseInstance = [self openDataBase:DATABASENAME];
}
if (nil == dataBaseInstance) {
[self createEditableCopyofDataBaseIfNeeded:YES];
}
}
return dataBaseInstance;
}
+(void)commitTransaction
{
char *errMessage;
sqlite3_exec(dataBaseInstance, "COMMIT", nil, nil, &errMessage);
}
+(void)beginTransaction
{
char *errMessage;
sqlite3_exec(dataBaseInstance, "BEGIN", nil, nil, &errMessage);
}
+(DataStatement*)statementWithQuery:(const char*)sql
{
[self sharedDataBase];
DataStatement *dataStatement = [DataStatement statementWithDB:dataBaseInstance withQuery:sql];
return dataStatement;
}
+(void)closeDataBase
{
sqlite3_close(dataBaseInstance);
dataBaseInstance = nil; //數據庫句柄一定要置空,不然重新建立連接的時候會有問題
}
+(void)alert
{
NSString *errorString = [NSString stringWithUTF8String: sqlite3_errmsg(dataBaseInstance)];
CLog(@"alert message:%@",errorString);
}
Datastatement.h
#import <Foundation/Foundation.h>
#import "sqlite3.h"
@interface DataStatement : NSObject
{
sqlite3_stmt* stmt;
}
+(id)statementWithDB:(sqlite3*)DB withQuery:(const char *)sql;
-(id)initWithDB:(sqlite3*)db withQuery:(const char *)sql;
// method
- (int)step;
- (void)reset;
- (int)getResultCount;
// Getter
- (NSString*)getString:(int)index;
- (int)getInt32:(int)index;
- (long long)getInt64:(int)index;
- (NSData*)getData:(int)index;
- (double)getDouble:(int)index;
// Binder
- (void)bindString:(NSString*)value forIndex:(int)index;
- (void)bindInt32:(int)value forIndex:(int)index;
- (void)bindInt64:(long long)value forIndex:(int)index;
- (void)bindData:(NSData*)data forIndex:(int)index;
- (void)bindDouble:(double)value forIndex:(int)index;
@end
Datastatement.m
//
// DataStatement.m
// mainPage
//
// Created by myiee on 11-11-3.
// Copyright (c) 2011年 __MyCompanyName__. All rights reserved.
//
#import "DataStatement.h"
@implementation DataStatement
-(void)dealloc
{
[super dealloc];
sqlite3_finalize(stmt);
}
-(id)initWithDB:(sqlite3 *)db withQuery:(const char *)sql
{
self = [super init];
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL)!=SQLITE_OK) {
NSAssert2(0, @"can not compare '%s',(%s)", sql, sqlite3_errmsg(db));
}
return self;
}
+(id)statementWithDB:(sqlite3 *)DB withQuery:(const char *)sql
{
return [[[DataStatement alloc]initWithDB:DB withQuery:sql]autorelease];
}
-(int)step
{
return sqlite3_step(stmt);
}
-(void)reset
{
sqlite3_reset(stmt);
}
- (int)getResultCount
{
return sqlite3_column_count(stmt);
}
-(NSString*)getString:(int)index
{
if (NULL != (char*)sqlite3_column_text(stmt, index)) {
return [NSString stringWithUTF8String:(char*)sqlite3_column_text(stmt, index)];
}
else
return nil;
}
-(int)getInt32:(int)index
{
return sqlite3_column_int(stmt, index);
}
-(long long)getInt64:(int)index
{
return sqlite3_column_int64(stmt, index);
}
-(NSData*)getData:(int)index
{
int length = sqlite3_column_bytes(stmt, index);
return [NSData dataWithBytes:sqlite3_column_blob(stmt, index) length:length];
}
-(double)getDouble:(int)index
{
return sqlite3_column_double(stmt, index);
}
-(void)bindData:(NSData *)data forIndex:(int)index
{
sqlite3_bind_blob(stmt, index, data.bytes, data.length, SQLITE_TRANSIENT);
}
-(void)bindString:(NSString *)value forIndex:(int)index
{
sqlite3_bind_text(stmt, index,[value UTF8String] , -1, SQLITE_TRANSIENT);
}
-(void)bindInt32:(int)value forIndex:(int)index
{
sqlite3_bind_int(stmt, index,value);
}
-(void)bindInt64:(long long)value forIndex:(int)index
{
sqlite3_bind_int64(stmt, index, value);
}
-(void)bindDouble:(double)value forIndex:(int)index
{
sqlite3_bind_double(stmt, index, value);
}
@end
DatabaseCenter.h
#import <Foundation/Foundation.h>
#import "sqlite3.h"
//#import "Users.h"
#import "DataConnection.h"
#import "DataStatement.h"
@interface DataBaseCenter : NSObject
{
sqlite3_stmt *stmt;
}
+ (void)createDatabase;
//user
+ (id)getLastLoginUser;
+ (BOOL)updateUser:(NSDictionary*)dictionary;
+ (id)getUserWithName:(NSString*)name;
@end
DatabaseCenter.m
+(void)createDatabase
{
[DataConnection sharedDataBase];
NSString *createUser = @"create table if not exists user(userId integer primary key,name text not null,password text not null,flag integer not null);";
//這個數據庫中只建立了一個user的數據表,當flag爲1的時候代表這條用戶的數據紀錄是最後一個合法登陸的數據用戶
[DataConnection exeCreate:createDataString];
}
+ (id)getLastLoginUser
{
static DataStatement *stmt = nil;
if (!stmt)
{
stmt = [DataConnection statementWithQuery:"select * from user where flag = 1"];
[stmt retain];
}
if (SQLITE_ROW != [stmt step]) {
[stmt reset];
return nil;
}
NSString *userName = [stmt getString:1];
NSString *password = [stmt getString:2];
NSDictionary *dic = [[NSDictionary alloc]initWithObjectsAndKeys:userName,@"name",password,@"password", nil];
return [dic autorelease];
}
+ (BOOL)updateUser:(NSDictionary*)dictionary //將當前的的數據的flag更新爲1 ,其他置爲0,當前的用戶數據不存在的時候插入到表中
{
NSDictionary *dic = [dictionary retain];
NSString *userName = [dic objectForKey:@"name"];
NSString *password = [dic objectForKey:@"password"];
int flag = [[dic objectForKey:@"flag"]intValue];
NSString *selectString = [NSString stringWithFormat:@"select * from user where name = '%@'",userName];
const char *cString = [selectString cStringUsingEncoding:NSUTF8StringEncoding ];
unsigned int r = [DataConnection getRowsWithQury:cString];
DataStatement *stmt = nil;
if (!stmt) {
stmt = [DataConnection statementWithQuery:"update user set flag = 0 where flag != 0"];
[stmt retain];
}
if (SQLITE_DONE != [stmt step]) {
[stmt release];
[stmt reset];
stmt = nil;
return NO;
}
[stmt release];
stmt = nil;
if (r ==1 ) {//當之前已經存在該數據的時候更新變爲1
NSString *stmtString = [NSString stringWithFormat:@"update user set flag = 1 where name = '%@'",userName];
stmt = [DataConnection statementWithQuery:[stmtString UTF8String]];
[stmt retain];
if (SQLITE_DONE != [stmt step]) {
[stmt release];
[stmt reset];
stmt = nil;
return NO;
}
[stmt release];
}
else
{
stmt = nil;
if (!stmt) {
stmt = [DataConnection statementWithQuery:"insert or replace into user(name,password,flag) values(?,?,?)"];
[stmt retain];
}
[stmt bindString:userName forIndex:1];
[stmt bindString:password forIndex:2];
[stmt bindInt32:flag forIndex:3];
if (SQLITE_DONE != [stmt step]) {
[stmt reset];
[stmt release];
return NO;
}
[stmt release];
}
return YES;
}
//根據用戶名獲取用戶的數據
+ (id)getUserWithName:(NSString *)name
{
DataStatement *stmt = nil;
NSString *selectString = [NSString stringWithFormat:@"select * from user where name = %@",name];
const char *cString = [selectString cStringUsingEncoding:NSUTF8StringEncoding];
if (!stmt)
{
stmt = [DataConnection statementWithQuery:cString];
[stmt retain];
}
if (SQLITE_ROW != [stmt step]) {
[stmt reset];
return nil;
}
NSString *userName = [stmt getString:1];
NSString *password = [stmt getString:2];
NSDictionary *dic = [[NSDictionary alloc]initWithObjectsAndKeys:userName,@"name",password,@"password", nil];
return [dic autorelease];
}
4.現在經過簡單的封裝,我們就能用數據庫了
現在我們能在任何一個地方使用這個單例了,現在我們新建一個文件TestDatabase文件中的使用他
- (void)loadView
{
[super loadView];
[DataBasecenter createDatabase];
NSDictionary *dic = [NSDictionary dicionaryValueAndkeys:@"name",@"name",@"1234567",@"password",@"1",@"flag"];
[DataBaseCenter updateUser:dic];
}
這樣我們就能使用數據庫了,其實挺簡單的。
4.我在這個例子中只有一個數據庫,所以用單例很方便,當然你想建立多個數據庫,那也是很簡單,一個數據庫對應的一個數據庫connection,一個connection可以對應多個statement,我這樣的封裝適合單個數據庫,你也可以封裝成工廠的方式,見前面我對xml解析的一文,也是很簡單的。
總結:對sqlite的使用,我之前看到一個很好的例子,我將轉過來作爲一個單獨的系列。
注:轉載請註明出處。