swift下FMDB的使用
swift下FMDB的使用
在IOS中可以使用的存儲結(jié)構(gòu)有很多,可以使用文件進行緩存,可以使用useDefault實現(xiàn)簡單狀態(tài)的存儲,此外IOS下有一個常用的數(shù)據(jù)庫框架–FMDB,它是對于SQLite的一層封裝,可以使用它完成基本的增刪查改,也可以對此完成事務(wù),回滾等復(fù)雜操作
對于FMDB的集成,我們可以直接使用cocoapod完成集成,就像如下的podfile
之后,就可以進行操作了,但是由于我使用的是swift,FMDB是使用OC語言封裝的庫,要使用的話,就應(yīng)該在項目的根目錄下面創(chuàng)建一個bridge.h,在其中導(dǎo)入我們的FMDB
加完以后,我們還需要再info.plist中,進行設(shè)置,使得我們的改動內(nèi)容生效,點擊項目–TARGETS–Build Settings,其中有一個設(shè)置是swift compiler - General設(shè)置其中OC橋接文件為之前自定義的文件
之后的話,就可以直接使用了,我們可以先定義一個公共的操作類,封裝數(shù)據(jù)的初始化和增刪查改等操作
先定義好我們的實體類對象
首先來說,這個類應(yīng)該是全局的單例對象,所以說,先設(shè)置一個static的對象,讓其他的類調(diào)用來獲取到對象,之后,在使用的時候要先打開db對象,這里需要注意的問題就是,對于這個數(shù)據(jù)庫,我們是通過一個文件路徑來生成的,如果原先就存在這個數(shù)據(jù)庫,會直接打開這個文件,如果不存在,就會先創(chuàng)建數(shù)據(jù)庫,在進行開啟數(shù)據(jù)庫的操作,值得注意的是,在FMDB中,使用數(shù)據(jù)庫以后要及時關(guān)閉數(shù)據(jù)庫,所以來說open和close一般是成對出現(xiàn)的
import UIKitclass FMDBManager: NSObject {static let shared = FMDBManager();var dbUrl : String?;var FMDBEntity : FMDatabase?;var FMDBQueue : FMDatabaseQueue?;//打開數(shù)據(jù)庫,也就是創(chuàng)建數(shù)據(jù)庫func opendb(dbName : String, tableName : String) {//在doc文件夾下面創(chuàng)建新的文件夾,用來儲存數(shù)據(jù)庫let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true);let docPath = paths[0] + "/\(dbName)";self.dbUrl = docPath;//創(chuàng)建新的數(shù)據(jù)庫self.FMDBEntity = FMDatabase.init(path: self.dbUrl);//如果數(shù)據(jù)庫存在,就直接打開,如果不存在,則會現(xiàn)在磁盤上創(chuàng)建數(shù)據(jù)庫,然后再打開if self.FMDBEntity!.open() {print("數(shù)據(jù)庫打開成功");//創(chuàng)建數(shù)據(jù)表self.initTable(t_name: tableName);}else {print("數(shù)據(jù)庫打開失敗");}//數(shù)據(jù)庫每次操作完成以后就應(yīng)該釋放資源self.FMDBEntity!.close();}func initTable(t_name : String) {let sql = "CREATE TABLE IF NOT EXISTS \(t_name)( \n" +"id INTEGER PRIMARY KEY AUTOINCREMENT, \n" +"name TEXT, \n" +"age INTEGER \n" +"); \n"if self.FMDBEntity!.executeUpdate(sql, withArgumentsIn: []) {print("數(shù)據(jù)表創(chuàng)建成功");}else {print("數(shù)據(jù)表創(chuàng)建失敗");}}}這樣的話,我們就完成了數(shù)據(jù)表的創(chuàng)建,如果要進行增刪查改,我們就可以借助于FMDatabase執(zhí)行對應(yīng)的sql代碼,對于FMDB來說,它和一般的數(shù)據(jù)庫沒有區(qū)別,所以說,原先使用的sql基本上沒有變化,下面舉個例子,如果我們要增加一條記錄,那么需要執(zhí)行的sql是
insert into table_name (cloum1, cloum2, cloum3...) values(value1, value2, value3...)接下來,我們就可以編寫一個方法來執(zhí)行我們的sql,一般來說有兩種方式
在這里,可以直接把參數(shù)嵌入到自定義的String中,拼接成完整的sql語句用來執(zhí)行,也可以使用?作為占位符,我使用的是占位符的方式,方法如下
而如果要進行查詢操作時,我們就會接觸到另外一個對象,那就是FMDB中的結(jié)果集FMResultSet,這個東西和jdbc中的結(jié)果集是相通的,可以進行逐行的遍歷,得到每條數(shù)據(jù),然后就可以進行相應(yīng)的解析,在組合成一個完整的對象,也就是下面的方法
func select(tableName : String, param : [String : AnyObject]) -> [PersonEntity] {let pId = param["id"];//定義增加的sqllet sql = "select * from \(tableName) where id = ?";//開啟數(shù)據(jù)庫連接,執(zhí)行sql語句var persons : [PersonEntity] = [];if self.FMDBEntity!.open() {//數(shù)據(jù)庫連接已打開,傳入sql和參數(shù)if let queryResult = self.FMDBEntity?.executeQuery(sql, withArgumentsIn: [pId ?? 0]) {while queryResult.next() {let id = queryResult.int(forColumn: "id");let name = queryResult.string(forColumn: "name") ?? "";let age = queryResult.int(forColumn: "age");let p = PersonEntity();p.initParam(id: Int(id), name: String(name), age: Int(age));persons.append(p);}}}self.FMDBEntity!.close();return persons;}下面還有刪除和修改的代碼,沒有什么特別之處了,就不再贅述了
func update(tableName : String, param : [String : AnyObject]) {//定義修改的sqllet sql = "update \(tableName) set name = ? where id = ?";//開啟數(shù)據(jù)庫連接,執(zhí)行sql語句if self.FMDBEntity!.open() {//數(shù)據(jù)庫連接已打開,傳入sql和參數(shù)if self.FMDBEntity!.executeUpdate(sql, withArgumentsIn: ["張老道", 1]) {print("操作完成");}else{print("操作失敗");}}self.FMDBEntity!.close();}func delete(tableName : String, param : [String : AnyObject]) {//定義刪除的sqllet sql = "delete from \(tableName) where id = ?";//開啟數(shù)據(jù)庫連接,執(zhí)行sql語句if self.FMDBEntity!.open() {//數(shù)據(jù)庫連接已打開,傳入sql和參數(shù)if self.FMDBEntity!.executeUpdate(sql, withArgumentsIn: [1]) {print("操作完成");}else{print("操作失敗");}}self.FMDBEntity!.close();}有點意思的這個數(shù)據(jù)庫里面的事務(wù)操作,在FMDB中事務(wù)操作依賴于一個隊列來實現(xiàn),那就是FMDatabaseQueue,先貼出來代碼,然后再分析一下,先是隊列的初始化
//執(zhí)行之前需要先初始化數(shù)據(jù)庫func openQueue(dbName : String, tableName : String) {let path = self.dbUrl ?? "";if path == "" {print("要先完成初始化");self.opendb(dbName: dbName, tableName: tableName);}self.FMDBQueue = FMDatabaseQueue.init(path: self.dbUrl);}之后執(zhí)行批量執(zhí)行的代碼
@objc func batchHandle() {print("批量插入");FMDBManager.shared.FMDBQueue?.inTransaction({ (db, rollback) inlet trueTable = "t_Student";let errorTable = "t_Sent";for i in 40..<50{var sql = "insert into \(trueTable) (name, age) values(?, ?)";if i == 45 {sql = "insert into \(errorTable) (name, age) values(?, ?)";}let result : Bool = db.executeUpdate(sql, withArgumentsIn: ["張啟山", i]);if result {print("插入數(shù)據(jù):\(i)");}else{print("出現(xiàn)錯誤,開始回滾");rollback.pointee = true;return ;}}})}所以來說,進行批量查詢的代碼關(guān)鍵就在inTransaction這個方法中,如果直接點進去,我們會到達源代碼中的這個位置
直接往里跳,會到具體的代碼實現(xiàn)
不難看出,接下來,我們會跳轉(zhuǎn)到beginTransaction方法,那這個方法執(zhí)行內(nèi)容又是什么呢,其實就只有一行代碼
- (BOOL)beginTransaction {BOOL b = [self executeUpdate:@"begin exclusive transaction"];if (b) {_isInTransaction = YES;}return b; }就是執(zhí)行了begin exclusive transaction,然后由于我們實現(xiàn)了源代碼里面的block,會在這條執(zhí)行以后粘貼上十條sql,然后根據(jù)shouldRollback的值決定最后的代碼,我們在自己的代碼執(zhí)行時,通過判斷每一插入語句的執(zhí)行結(jié)果,決定返回的布爾值,然后如果每條代碼都能執(zhí)行,就提交commit,所有代碼提交生效,否則就提交rollback,所有代碼回滾,完成了事務(wù)的功能
參考文章
第一篇文章
第二篇文章
第三篇文章
對于更多的FMDB和Model封裝操作,可以參考下面這篇文章,所的也很豐富,有興趣的可以自己研究一下
實體類與數(shù)據(jù)庫表的關(guān)聯(lián)映射
總結(jié)
以上是生活随笔為你收集整理的swift下FMDB的使用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 网络渗透就业学习路线
- 下一篇: Prim最小生成树算法