框架地址:[https://github.com/ccgus/fmdb]
-
下載框架
Snip20160912_6.png -
首先要明白框架中幾個重要的類
- FMDatabase 代表一個數據庫 并且可以使用它執行sqlite語句
- FMDatabaseQueue 是線程安全的存儲跟讀取數據 這里有一個概念---
事物
- FMResultSet 結果集 從數據庫中讀取數據的集合
使用之前會發現編譯報錯,需要先在Build Phases->Link Binary With Libraries->導入libsqlite3.tbd 再次編譯就??
FMDatabase
- 首先我們我們不考慮線程安全下使用FMDatabase來創建數據庫實現離線緩存
- 導入
#import "FMDB.h"
- 導入
// 1.獲得數據庫路徑
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"daba.sqlist"];
// 2.創建數據對象
FMDatabase *dataBase = [FMDatabase databaseWithPath:path];
// 3.打開數據庫的時候首先判斷當前數據庫是否存在, 如果不存儲在就創建一個并打開, 如果存儲在那么就不創建直接打開
BOOL isSuccess = [dataBase open];
if (!isSuccess) {
NSLog(@"打開數據庫失敗");
}else{
NSLog(@"打開數據庫成功");
}
}
創建好數據庫之后,接下來就是根據我們的需求在數據庫中中創建表了,一個數據庫可以創建多張表, 一張表包含多個字段,也就是對應表的
column
, 表是有row跟column
構成, 有點類似Excle表細節不多說 創建一個完整的字段表
// 數據庫前提是open狀態
/**
* PRIMARY KEY 主鍵
* AUTOINCREMENT 自動增量
* UNIQUE 唯一
* DEFAULT 默認值
* @param INTEGER 整型
* @param TEXT 文本
* @param REAL 浮點型
* @param
* @param BLOB 二進制
*/
BOOL isSuccess = [dataBase executeUpdate:@"CREATE TABLE IF NOT EXIST t_table (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL UNIQUE, age INTEGER NOT NULL UNIQUE DEFAULT 0, score REAL NOT NULL unique, data BLOB);"];
if (!isSuccess) {
NSLog(@"創建表成功");
}else{
NSLog(@"創建表失敗");
}
- 表創建完成了,接下來就是我們利用FMDatabase對象要插入數據了, 這里我們了解一下插入數據的常見3中寫法
/**此種方式后面拼接的參數必須為對象 不可以為int double等基本數據類型*/
[dataBase executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
/**此種方式后面拼接的參數可以為int double等基本數據類型 因為是使用的占位符*/
[dataBase executeUpdateWithFormat:@"insert into t_table(name, age, score, data) values(%@, %d , %f, %@)", @"jake", 12, 91.0, [NSData data]];
/**此種方式后面拼接的參數必須為對象 不可以為int double等基本數據類型 將對象依次防近視數組*/
[dataBase executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)" withArgumentsInArray:@[@12, @91.0, [NSData data]]];
-注意
當我們存儲表中BLOB 對應的字段如果為字典
的時候,這個時候我們不應該把字典
往里存,應當使用[NSKeyedArchiver archivedDataWithRootObject:<#(nonnull id)#>]
將字典轉換成NSData
類型, 這樣當我們取出數據的時候取出的是NSData類型,再將NSData類型數據通過[NSKeyedUnarchiver unarchiveObjectWithData:<#(nonnull NSData *)#>];
反歸檔得到就是字典,如果直接存字典,從數據數據庫中取出的是字符串
, 字典裝模型時候會報錯
- 下面再說一下查表, 更行表 刪除表數據就不說了,跟插入數據一樣 自己研究
- 書寫格式幾乎相同 就是返回結果是
FMResultSet
類型(結果集), 這時候根據遍歷結果集取出每一條數據
/**此種方式后面拼接的參數必須為對象 不可以為int double等基本數據類型*/
[dataBase executeQuery:@"select *From t_table;"];
/**此種方式后面拼接的參數可以為int double等基本數據類型 因為是使用的占位符*/
[dataBase executeQueryWithFormat:@"SELECT name, age, score from t_table where name = %@", @"jake"];
/**此種方式后面拼接的參數必須為對象 不可以為int double等基本數據類型 將對象依次防近視數組*/
[dataBase executeQuery:@"select *from t_table where age > ?" withArgumentsInArray:@[@12]];
- 拿查整個表的全部數據為例
FMResultSet * resultSet = [dataBase executeQuery:@"select *From t_table;"];
while ([resultSet next]) {
// 通過字段獲取 文本數據
[resultSet stringForColumn:@"name"];
// 也可以通過Column來獲取
[resultSet stringForColumnIndex:2];
// 通過字段獲取 對象數據
[resultSet objectForColumnName:@"dict"];
}
- 關于FMResultSet使用結合如下
/* 獲取下一個記錄 */
- (BOOL)next;
/* 獲取記錄有多少列 */
- (int)columnCount;
/* 通過列名得到列序號,通過列序號得到列名 */
- (int)columnIndexForName:(NSString *)columnName;
- (NSString *)columnNameForIndex:(int)columnIdx;
/* 獲取存儲的整形值 */
- (int)intForColumn:(NSString *)columnName;
- (int)intForColumnIndex:(int)columnIdx;
/* 獲取存儲的長整形值 */
- (long)longForColumn:(NSString *)columnName;
- (long)longForColumnIndex:(int)columnIdx;
/* 獲取存儲的布爾值 */
- (BOOL)boolForColumn:(NSString *)columnName;
- (BOOL)boolForColumnIndex:(int)columnIdx;
/* 獲取存儲的浮點值 */
- (double)doubleForColumn:(NSString *)columnName;
- (double)doubleForColumnIndex:(int)columnIdx;
/* 獲取存儲的字符串 */
- (NSString *)stringForColumn:(NSString *)columnName;
- (NSString *)stringForColumnIndex:(int)columnIdx;
/* 獲取存儲的日期數據 */
- (NSDate *)dateForColumn:(NSString *)columnName;
- (NSDate *)dateForColumnIndex:(int)columnIdx;
/* 獲取存儲的二進制數據 */
- (NSData *)dataForColumn:(NSString *)columnName;
- (NSData *)dataForColumnIndex:(int)columnIdx;
/* 獲取存儲的UTF8格式的C語言字符串 */
- (const unsigned cahr *)UTF8StringForColumnName:(NSString *)columnName;
- (const unsigned cahr *)UTF8StringForColumnIndex:(int)columnIdx;
/* 獲取存儲的對象,只能是NSNumber、NSString、NSData、NSNull */
- (id)objectForColumnName:(NSString *)columnName;
- (id)objectForColumnIndex:(int)columnIdx;
FMDatabaseQueue
如果項目中開啟多個線程同時訪問一個數據庫的時候,需要考慮到線程安全的問題了,那么就要使用這個類來對數據庫操作了, 那么我們還要理解一個概念
事物
常說開啟事物 提交事物 回滾事物 是什么意思呢? 為什么需要開啟事物呢說個情形就明白了,加入我們像一個數據庫表中插入一百條數據, 我們可能會執行一百條SQLite語句,如果當我們執行到一半的時候出錯了,那么我們需要
回滾
, 讓之前執行的的數據恢復之前數據,也就是一句話,我們需要所有的語句都執行成功才生效,那么我們就需要開啟事物
,當確定所有的語句都執行成功就提交事物
, 如果中途出錯,那么就回滾事物
首先我們不開啟事物,就線程安全來使用FMDB
// 1.獲得數據庫路徑
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"daba.sqlist"];
// 創建FMDatabaseQueue 同時會創建數據庫 如果數據庫不存在
FMDatabaseQueue *baseQueue = [FMDatabaseQueue databaseQueueWithPath:path];
- 當我們對數據庫進行CRUDde的時候調用
- (void)inDatabase:(void (^)(FMDatabase *db))block
, 在block回調給我的FMDatabase對象進行操作 ,操作跟上面一樣的 例如
[baseQueue inDatabase:^(FMDatabase *db) {
// 打開數據庫 創建表
BOOL isSuccess = [db open];
if (!isSuccess) {
NSLog(@"打開數據庫失敗");
}else{
NSLog(@"打開數據庫成功");
// 插入數據
[db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
}
}];
- 使用一下開啟事物, 加入我們插入同時插入十條數據
// 1.獲得數據庫路徑
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"daba.sqlist"];
// 創建FMDatabaseQueue 同時會創建數據庫 如果數據庫不存在
FMDatabaseQueue *baseQueue = [FMDatabaseQueue databaseQueueWithPath:path];
[baseQueue inDatabase:^(FMDatabase *db) {
// 打開數據庫 創建表
BOOL isSuccess = [db open];
if (!isSuccess) {
NSLog(@"打開數據庫失敗");
}else{
NSLog(@"打開數據庫成功");
// 開啟事物
[db beginTransaction];
// 插入數據
[db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
[db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
[db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
[db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
[db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
[db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
// 也可以在中途回滾 就是該次對數據庫的操作不生效 通常中途一般不回滾
[db rollback];
[db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
[db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
[db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
[db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
[db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
[db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
// 提交事物
[db commit];
}
}];
- 其實FMDB內部已經幫我們封裝好,只需要調用FMDatabaseQueue對象方法
- (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block
[baseQueue inTransaction:^(FMDatabase *db, BOOL *rollback) {
[db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
[db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
[db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
[db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
[db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
[db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
// 如果中途想回滾 就這樣操作
*rollback = YES;
[db rollback];
[db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
[db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
[db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
[db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
[db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
[db executeUpdate:@"insert into t_table(name, age, score, data) values(?, ? , ?, ?)", @"jake", @12, @91.0, [NSData data]];
}];
- 下班了,不寫了,大家如果發現有誤,謝謝反饋給我????