1.什么是FMDB
iOS中使用C語言函數(shù)對原生SQLite數(shù)據(jù)庫進(jìn)行增刪改查操作,復(fù)雜麻煩适篙,于是,就出現(xiàn)了一系列將SQLite API封裝的庫,如FMDB
FMDB是針對libsqlite3框架進(jìn)行封裝的三方草添,它以O(shè)C的方式封裝了SQLite的C語言的API,使用步驟與SQLite相似
FMDB的優(yōu)點(diǎn)是:
(1) 使用時(shí)面向?qū)ο蠖笾伲苊饬藦?fù)雜的C語言代碼
(2) 對比蘋果自帶的Core Data框架远寸,更加輕量級和靈活
(3) 提供多線程安全處理數(shù)據(jù)庫操作方法,保證多線程安全跟數(shù)據(jù)準(zhǔn)確性
FMDB缺點(diǎn):
(1) 因?yàn)槭荗C語言開發(fā)屠凶,只能在iOS平臺上使用驰后,所以實(shí)現(xiàn)跨平臺操作時(shí)存在限制性
FMDB 在Git上的下載鏈接地址:https://github.com/ccgus/fmdb
2.主要類型
FMDatabase:一個(gè)FMDatabase對象代表一個(gè)單獨(dú)的SQLite數(shù)據(jù)庫,通過SQLite語句執(zhí)行數(shù)據(jù)庫的增刪改查操作
FMResultSet:使用FMDatabase對象查詢數(shù)據(jù)庫后的結(jié)果集
FMDatabaseQueue:用于多線程操作數(shù)據(jù)庫矗愧,它保證線程安全
3.FMDB使用方式
(1) GItHub中下載FMDB灶芝,將文件導(dǎo)入工程中
(2) 導(dǎo)入libsqlite3.0框架,導(dǎo)入頭文件FMDatabase.h
(3) 創(chuàng)建數(shù)據(jù)庫路徑唉韭,創(chuàng)建數(shù)據(jù)庫夜涕,操作前開啟數(shù)據(jù)庫,構(gòu)建操作SQLite語句属愤,數(shù)據(jù)庫執(zhí)行增刪改查操作女器,操作完關(guān)閉數(shù)據(jù)庫
4.FMDB基本使用示例:??
(0) 創(chuàng)建Person類
@interface PersonVO : NSObject
@property (nonatomic, assign) int ID;
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *phone;
@property (nonatomic, assign) int score;
@end
(1) 使用FMDBbase類創(chuàng)建數(shù)據(jù)庫
//1.創(chuàng)建database路徑
NSString *docuPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
NSString *dbPath = [docuPath stringByAppendingPathComponent:@"test.db"];
NSLog(@"!!!dbPath = %@",dbPath);
//2.創(chuàng)建對應(yīng)路徑下數(shù)據(jù)庫
db = [FMDatabase databaseWithPath:dbPath];
//3.在數(shù)據(jù)庫中進(jìn)行增刪改查操作時(shí),需要判斷數(shù)據(jù)庫是否open住诸,如果open失敗驾胆,可能是權(quán)限或者資源不足,數(shù)據(jù)庫操作完成通常使用close關(guān)閉數(shù)據(jù)庫
[db open];
if (![db open]) {
NSLog(@"db open fail");
return;
}
//4.數(shù)據(jù)庫中創(chuàng)建表(可創(chuàng)建多張)
NSString *sql = @"create table if not exists t_student ('ID' INTEGER PRIMARY KEY AUTOINCREMENT,'name' TEXT NOT NULL, 'phone' TEXT NOT NULL,'score' INTEGER NOT NULL)";
//5.執(zhí)行更新操作 此處database直接操作贱呐,不考慮多線程問題丧诺,多線程問題,用FMDatabaseQueue 每次數(shù)據(jù)庫操作之后都會返回bool數(shù)值吼句,YES锅必,表示success,NO惕艳,表示fail,可以通過 @see lastError @see lastErrorCode @see lastErrorMessage
BOOL result = [db executeUpdate:sql];
if (result) {
NSLog(@"create table success");
}
[db close];
(2) 插入命令sql語句
/**
增刪改查中 除了查詢(executeQuery)搞隐,其余操作都用(executeUpdate)
//1.sql語句中跟columnname 綁定的value 用 ?表示远搪,不加‘’劣纲,可選參數(shù)是對象類型如:NSString,不是基本數(shù)據(jù)結(jié)構(gòu)類型如:int谁鳍,方法自動(dòng)匹配對象類型
- (BOOL)executeUpdate:(NSString*)sql, ...;
//2.sql語句中跟columnname 綁定的value 用%@/%d表示癞季,不加‘’
- (BOOL)executeUpdateWithFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(1,2);
//3.sql語句中跟columnname 綁定的value 用 劫瞳?表示的地方依次用 (NSArray *)arguments 對應(yīng)的數(shù)據(jù)替代
- (BOOL)executeUpdate:(NSString*)sql withArgumentsInArray:(NSArray *)arguments;
//4.同3 ,區(qū)別在于多一個(gè)error指針绷柒,記錄更新失敗
- (BOOL)executeUpdate:(NSString*)sql values:(NSArray * _Nullable)values error:(NSError * _Nullable __autoreleasing *)error;
//5.同3志于,區(qū)別在于用 ? 表示的地方依次用(NSDictionary *)arguments中對應(yīng)的數(shù)據(jù)替代
- (BOOL)executeUpdate:(NSString*)sql withParameterDictionary:(NSDictionary *)arguments;
- (BOOL)executeUpdate:(NSString*)sql withVAList: (va_list)args;
*/
//0.直接sql語句
// BOOL result = [db executeUpdate:@"insert into 't_student' (ID,name,phone,score) values(110,'x1','11',83)"];
//1.
// BOOL result = [db executeUpdate:@"insert into 't_student'(ID,name,phone,score) values(?,?,?,?)",@111,@"x2",@"12",@23];
//2.
// BOOL result = [db executeUpdateWithFormat:@"insert into 't_student' (ID,name,phone,score) values(%d,%@,%@,%d)",112,@"x3",@"13",43];
//3.
BOOL result = [db executeUpdate:@"insert into 't_student'(ID,name,phone,score) values(?,?,?,?)" withArgumentsInArray:@[@113,@"x3",@"13",@53]];
if (result) {
NSLog(@"insert into 't_studet' success");
[self showAlertWithTitle:@"insert success" message:nil person:nil];
} else {
[self showAlertWithTitle:[db lastError].description message:nil person:nil];
}
[db close];
(3) 刪除命令sql語句
[db open];
///0.直接sql語句
// BOOL result = [db executeUpdate:@"delete from 't_student' where ID = 110"];
//1.
// BOOL result = [db executeUpdate:@"delete from 't_student' where ID = ?",@(111)];
//2.
// BOOL result = [db executeUpdateWithFormat:@"delete from 't_student' where ID = %d",112];
//3.
BOOL result = [db executeUpdate:@"delete from 't_student' where ID = ?" withArgumentsInArray:@[@113]];
if (result) {
NSLog(@"delete from 't_student' success");
[self showAlertWithTitle:@"delete success" message:nil person:nil];
} else {
[self showAlertWithTitle:[db lastError].description message:nil person:nil];
}
[db close];
(4) 更新命令sql語句
[db open];
//0.直接sql語句
// BOOL result = [db executeUpdate:@"update 't_student' set ID = 110 where name = 'x1'"];
//1.
// BOOL result = [db executeUpdate:@"update 't_student' set ID = ? where name = ?",@111,@"x2" ];
//2.
// BOOL result = [db executeUpdateWithFormat:@"update 't_student' set ID = %d where name = %@",113,@"x3" ];
//3.
BOOL result = [db executeUpdate:@"update 't_student' set ID = ? where name = ?" withArgumentsInArray:@[@113,@"x3"]];
if (result) {
NSLog(@"update 't_student' success");
[self showAlertWithTitle:@"update success" message:nil person:nil];
} else {
[self showAlertWithTitle:[db lastError].description message:nil person:nil];
}
[db close];
(5) 查詢命令sql語句
/**
FMResultSet根據(jù)column name獲取對應(yīng)數(shù)據(jù)的方法
intForColumn:
longForColumn:
longLongIntForColumn:
boolForColumn:
doubleForColumn:
stringForColumn:
dataForColumn:
dataNoCopyForColumn:
UTF8StringForColumnIndex:
objectForColumn:
*/
[db open];
//0.直接sql語句
// FMResultSet *result = [db executeQuery:@"select * from 't_student' where ID = 110"];
//1.
// FMResultSet *result = [db executeQuery:@"select *from 't_student' where ID = ?",@111];
//2.
// FMResultSet *result = [db executeQueryWithFormat:@"select * from 't_student' where ID = %d",112];
//3.
FMResultSet *result = [db executeQuery:@"select * from 't_student' where ID = ?" withArgumentsInArray:@[@113]];
//4
// FMResultSet *result = [db executeQuery:@"select * from 't_sutdent' where ID = ?" withParameterDictionary:@{@"ID":@114}];
NSMutableArray *arr = [NSMutableArray array];
while ([result next]) {
PersonVO *person = [PersonVO new];
person.ID = [result intForColumn:@"ID"];
person.name = [result stringForColumn:@"name"];
person.phone = [result stringForColumn:@"phone"];
person.score = [result intForColumn:@"score"];
[arr addObject:person];
NSLog(@"從數(shù)據(jù)庫查詢到的人員 %@",person.name);
[self showAlertWithTitle:@"query success" message:nil person:person];
}
5.FMDB的事務(wù)
(1) 事務(wù)定義:
事務(wù)(Transaction)是并發(fā)操作的基本單位废睦,是指單個(gè)邏輯工作單位執(zhí)行的一系列操作序列伺绽,這些操作要不都成功,要不就不成功嗜湃,事務(wù)是數(shù)據(jù)庫維護(hù)數(shù)據(jù)一致性的單位奈应,在每個(gè)事務(wù)結(jié)束時(shí),都能保證數(shù)據(jù)一致性與準(zhǔn)確性购披,通常事務(wù)跟程序是兩個(gè)不同的概念杖挣,一個(gè)程序中包含多個(gè)事務(wù),事務(wù)主要解決并發(fā)條件下操作數(shù)據(jù)庫刚陡,保證數(shù)據(jù)
(2) 事務(wù)特征:
原子性(Atomic):事務(wù)中包含的一系列操作被看作一個(gè)邏輯單元惩妇,這個(gè)邏輯單元要不全部成功,要不全部失敗
一致性(Consistency):事務(wù)中包含的一系列操作筐乳,只有合法的數(shù)據(jù)被寫入數(shù)據(jù)庫屿附,一些列操作失敗之后,事務(wù)會滾到最初創(chuàng)建事務(wù)的狀態(tài)
隔離性(Isolation):對數(shù)據(jù)進(jìn)行修改的多個(gè)事務(wù)之間是隔離的哥童,每個(gè)事務(wù)是獨(dú)立的,不應(yīng)該以任何方式來影響其他事務(wù)
持久性(Durability)事務(wù)完成之后褒翰,事務(wù)處理的結(jié)果必須得到固化贮懈,它對于系統(tǒng)的影響是永久的,該修改即使出現(xiàn)系統(tǒng)固執(zhí)也將一直保留优训,真實(shí)的修改了數(shù)據(jù)庫
(3) 事務(wù)語句:
/**
transaction:事務(wù) 開啟一個(gè)事務(wù)執(zhí)行多個(gè)任務(wù)朵你,效率高
1.fmdb 封裝transaction 方法,操作簡單
- (BOOL)beginTransaction;
- (BOOL)beginDeferredTransaction;
- (BOOL)beginImmediateTransaction;
- (BOOL)beginExclusiveTransaction;
- (BOOL)commit;
- (BOOL)rollback;
等等
*/
開啟事務(wù) :beginTransaction
回滾事務(wù):rollback
提交事務(wù):commit
(4) 事務(wù)代碼
用事務(wù)處理一系列數(shù)據(jù)庫操作揣非,省時(shí)效率高
- (void)handleTransaction:(UIButton *)sender {
NSString *documentPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
NSString *dbPath = [documentPath stringByAppendingPathComponent:@"test1.db"];
FMDatabase *db = [[FMDatabase alloc]initWithPath:dbPath];
[db open];
if (![db isOpen]) {
return;
}
BOOL result = [db executeUpdate:@"create table if not exists text1 (name text,age,integer,ID integer)"];
if (result) {
NSLog(@"create table success");
}
//1.開啟事務(wù)
[db beginTransaction];
NSDate *begin = [NSDate date];
BOOL rollBack = NO;
@try {
//2.在事務(wù)中執(zhí)行任務(wù)
for (int i = 0; i< 500; i++) {
NSString *name = [NSString stringWithFormat:@"text_%d",i];
NSInteger age = i;
NSInteger ID = i *1000;
BOOL result = [db executeUpdate:@"insert into text1(name,age,ID) values(:name,:age,:ID)" withParameterDictionary:@{@"name":name,@"age":[NSNumber numberWithInteger:age],@"ID":@(ID)}];
if (result) {
NSLog(@"在事務(wù)中insert success");
}
}
}
@catch(NSException *exception) {
//3.在事務(wù)中執(zhí)行任務(wù)失敗抡医,退回開啟事務(wù)之前的狀態(tài)
rollBack = YES;
[db rollback];
}
@finally {
//4. 在事務(wù)中執(zhí)行任務(wù)成功之后
rollBack = NO;
[db commit];
}
NSDate *end = [NSDate date];
NSTimeInterval time = [end timeIntervalSinceDate:begin];
NSLog(@"在事務(wù)中執(zhí)行插入任務(wù) 所需要的時(shí)間 = %f",time);
}
未使用事務(wù)執(zhí)行一系列操作
-(void)handleNotransaction:(UIButton *)sender {
NSString *documentPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
NSString *dbPath = [documentPath stringByAppendingPathComponent:@"test1.db"];
FMDatabase *db = [FMDatabase databaseWithPath:dbPath];
[db open];
if (![db isOpen]) {
return;
}
BOOL result = [db executeUpdate:@"create table if not exists text2('ID' INTEGER PRIMARY KEY AUTOINCREMENT,name TEXT,age INTRGER)"];
if (!result) {
[db close];
}
NSDate *begin = [NSDate date];
for (int i = 0; i< 500; i++) {
NSString *name = [NSString stringWithFormat:@"text_%d",i];
NSInteger age = i;
NSInteger ID = i *1000;
BOOL result = [db executeUpdate:@"insert into text2(name,age,ID) values(:name,:age,:ID)" withParameterDictionary:@{@"name":name,@"age":[NSNumber numberWithInteger:age],@"ID":@(ID)}];
if (result) {
NSLog(@"不在事務(wù)中insert success");
}
}
NSDate *end = [NSDate date];
NSTimeInterval time = [end timeIntervalSinceDate:begin];
NSLog(@"不在事務(wù)中執(zhí)行插入任務(wù) 所需要的時(shí)間 = %f",time);
}
比較結(jié)果如下:
在事務(wù)中執(zhí)行插入任務(wù) 所需要的時(shí)間 = 0.426221
不在事務(wù)中執(zhí)行插入任務(wù) 所需要的時(shí)間 = 0.790417
- 附練習(xí)demo:https://github.com/sisios/fmdb_demo
Realm使用方法:http://www.reibang.com/p/73b1f509a41f
note: 由于本人水平有限,文中出現(xiàn)錯(cuò)誤或者不足之處在所難免早敬,敬請各位高人批評指正忌傻。