我在寫UDUserDefaultsModel(文章鏈接,github)這個庫時曾經立下一個flag:要寫一個基于model來存取數(shù)據(jù)庫的庫械荷,最近剛離職共耍,所以就整合了一下,希望大家多多支持吨瞎。
在iOS開發(fā)過程當中痹兜,難免用到數(shù)據(jù)庫,以FMDB居多颤诀。以下是一個根據(jù)年齡篩選數(shù)據(jù)的sql語句:
select * from Student where age > 10 and age < 20 or age > 30 order by age desc limit 20
這樣寫其實沒什么問題字旭,但是在我個人看來難以接受,字符串看起來太別扭崖叫。比如我再添加一個條件遗淳,那么就需要修改整個字符串了。
如果可以很好的控制sql語句心傀,將大大提高編程效率屈暗。為此,YIIFMDB就改善了這個缺陷:純面向對象脂男,直接操作Model养叛,完全不需要寫sql語句。
其靈感源自于php的Yii 2架構宰翅,因為我在看php代碼當中弃甥,我發(fā)現(xiàn)根本就看不到sql語句,而php程序猿也說:“我們的工作就是操作數(shù)據(jù)庫堕油,但是卻不寫sql語句”潘飘。
以下是YIIFMDB詳細用法:
YIIFMDB有兩個類:YIIFMDB和YIIParameters。其中YIIFMDB封裝了數(shù)據(jù)庫相關的操作掉缺,比如增刪改查之類卜录,而YIIParameters則封裝了where之后的參數(shù),比如上段代碼當中的:
age > 10 and age < 20 or age > 30 order by age desc limit 20
就可以在YIIParameters當中完成眶明。
接下來逐一介紹YIIParameters類和YIIFMDB類的使用:
YIIParameters類
sql語句當中where之后的參數(shù)基本上由以下模塊構成:
- and(與操作)
- or(或操作)
- order by(排序)
- limit(數(shù)量限制)
其中的and和or又要配置“>,<,=,>=,<=,!=,like”關系艰毒,order by又有“ase,dese”的排序操作搜囱。
YIIParameters這個類就包含了以上所有元素丑瞧。以上面的where之后的sql語句為例柑土,具體用法如下:
// 初始化YIIParameters
YIIParameters *parameters = [[YIIParameters alloc] init];
// 執(zhí)行and操作,將age限制在10-20之間
// age > 10,YIIParametersRelationTypeGreaterThan標志">"
[parameters andWhere:@"age" value:@"10" relationType:YIIParametersRelationTypeGreaterThan];
// age < 20,YIIParametersRelationTypeLessThan標志"<"
[parameters andWhere:@"age" value:@"20" relationType:YIIParametersRelationTypeLessThan];
// 以上是and绊汹,也就是形成的sql語句為: age > 10 and age < 20
// 執(zhí)行or操作稽屏,將age限制在age > 30 以上
[parameters orWhere:@"age" value:@"30" relationType:YIIParametersRelationTypeGreaterThan];
// 根據(jù)age進行降序排列
// YIIParametersOrderTypeDesc表示降序"desc",YIIParametersOrderTypeAsc
[parameters orderByColumn:@"age" orderType:YIIParametersOrderTypeDesc];
// 將數(shù)據(jù)的個數(shù)限制在20個
parameters.limitCount = 20;
配置完畢,驗證其是否配置正確西乖,那么可以調用一下方法就行了:
NSLog(@"where參數(shù)為:%@", parameters.whereParameters);
當然狐榔,如果參數(shù)都沒法配置了,則可以設置whereParameters获雕。而對于YIIParameters更詳細的解釋請參考 YIIFMDB中的YIIParameters.h薄腻。
YIIFMDB類
YIIParameters用來配置sql語句當中where之后的參數(shù),而YIIFMDB類則是對數(shù)據(jù)庫操作的進一步封裝届案,具體如下:
獲取YIIFMDB單例
YIIFMDB *db = [YIIFMDB shareDatabase]; // 推薦使用
// 或者
YIIFMDB *db = [YIIFMDB shareDatabaseForName:@"ABC.sqlite" path:path]; // 自定義數(shù)據(jù)庫名字和路徑庵楷,在第一次實例的時候傳入,以后使用上面方法即可楣颠。
主鍵的字段
@property (nonatomic, readonly, copy) NSString *primaryKey; // 返回"yii_pkID",我自己在創(chuàng)建數(shù)據(jù)庫是配置的主鍵字段
是否打印log
@property (nonatomic, assign) BOOL shouldOpenDebugLog; // 默認為NO尽纽,設為YES,會在控制器后臺打印數(shù)據(jù)庫操作相關的一些信息
創(chuàng)建一張表
[[YIIFMDB shareDatabase] createTableWithModelClass:[LCPersonModel class] excludedProperties:nil tableName:@"Person"];
此方法是創(chuàng)建一張名為@"Person"表童漩,并且蜓斧,表里面的字段也就是LCPersonModel里面的屬性,字段的數(shù)據(jù)類型也對應LCPersonModel里面的數(shù)據(jù)類型
插入一條數(shù)據(jù)(增)
LCPersonModel *model = [[LCPersonModel alloc] init];
model.name = [NSString stringWithFormat:@"lc%d", (arc4random() % 100)];
model.gender = arc4random() % 2;
model.age = arc4random() % 80;
model.floatNumber = (arc4random() % 20) / 100.0;
model.doubleNumber = (arc4random() % 20) / 100.0;
model.isMan = arc4random() % 2;
model.number = @(arc4random() % 10);
YIIFMDB *db = [YIIFMDB shareDatabase];
BOOL isSuccess = [db insertWithModel:model tableName:tableName]; //插入一條數(shù)據(jù)
[db insertWithModels:@[model] tableName:tableName]; // 批量插入數(shù)據(jù)
刪除數(shù)據(jù)(刪)
-(BOOL)deleteFromTable:(NSString * _Nonnull)tableName whereParameters:(YIIParameters *)parameters; // 根據(jù)參數(shù)刪除一條數(shù)據(jù),YIIParameters參考上面
-(BOOL)deleteAllDataFromTable:(NSString * _Nonnull)tableName; // 刪除表中的所有數(shù)據(jù)
YIIFMDB *db = [YIIFMDB shareDatabase];
YIIParameters *parameters = [[YIIParameters alloc] init];
// db.primaryKey 是數(shù)據(jù)庫的主鍵,這條語句意思是刪除主鍵 = 1的那條數(shù)據(jù)
[parameters andWhere:db.primaryKey value:@"1" relationType:YIIParametersRelationTypeEqualTo];
[db deleteFromTable:tableName whereParameters:parameters];
更改數(shù)據(jù)(改)
-(BOOL)updateTable:(NSString * _Nonnull)tableName dictionary:(NSDictionary * _Nonnull)dictionary whereParameters:(YIIParameters *)parameters; // 更新一條數(shù)據(jù)
YIIFMDB *db = [YIIFMDB shareDatabase];
YIIParameters *parameters = [[YIIParameters alloc] init];
// 參數(shù)設置為主鍵 = 10
[parameters andWhere:db.primaryKey value:@"10" relationType:YIIParametersRelationTypeEqualTo];
// 將主鍵為10的那條數(shù)據(jù)的name更改為monkey
[db updateTable:tableName dictionary:@{@"name": @"monkey"} whereParameters:parameters];
查詢數(shù)據(jù)
-(NSArray *)queryFromTable:(NSString * _Nonnull)tableName model:(Class _Nonnull)modelClass whereParameters:(YIIParameters *)parameters; // 根據(jù)YIIParameters條件從表為tableName的查詢數(shù)據(jù)
YIIFMDB *db = [YIIFMDB shareDatabase];
YIIParameters *parameters = [[YIIParameters alloc] init];
[parameters andWhere:db.primaryKey value:@"5" relationType:YIIParametersRelationTypeLessThan];
NSLog(@"主鍵小于5的數(shù)據(jù):%@", [db queryFromTable:tableName model:[LCPersonModel class] whereParameters:parameters]);
除了增刪改查之外睁冬,YIIFMDB還提供了增加一個屬性挎春,刪除一張表,獲取表中所有字段名豆拨,獲取表中數(shù)據(jù)個數(shù)直奋,表是否存在,求和施禾,求平均值脚线,最大值,最小值等功能弥搞,詳情請參考YIIFMDB的文檔邮绿。
線程安全操作(隊列和事務)
由于FMDB本身就是是不安全的,上面的方法也是不安全的,為了保證其安全則需要結合隊列和事務操作,參考FMDB的隊列和事務译柏。
-(void)inDatabase:(dispatch_block_t)block; // 將數(shù)據(jù)庫相關操作寫在block里可保證線程安全
YIIFMDB *db = [YIIFMDB shareDatabase];
[db inDatabase:^{
// 增刪改查放在此代碼塊里執(zhí)行則可以保證線程安全
}];
-(void)inTransaction:(void(^)(BOOL *rollback))block; // 在block里寫入代碼可執(zhí)行回滾操作
YIIFMDB *db = [YIIFMDB shareDatabase];
[db inTransaction:^(BOOL *rollback) {
// 如果某一個操作失誤炫七,則可以執(zhí)行回滾操作
BOOL isSuccess = YES; // 數(shù)據(jù)庫操作是否操作成功
if (!isSuccess) {
*rollback = YES; // 回滾操作
return ;
}
}];
這里還有兩個缺陷:
- 未支持聯(lián)表查詢
- 未支持Model當中套Model的插入观蜗。
如果是聯(lián)表查詢的話,那么需要獲取到YIIFMDB單例的"currentDatabase"來實現(xiàn)聯(lián)表查詢持搜,而Model套Model的备韧,則最好是創(chuàng)建兩張表酱鸭。