import UIKit class SQLiteManager: NSObject { private static let manager: SQLiteManager = SQLiteManager() /// 單粒 class func shareManager() ->SQLiteManager { return manager } // 數據庫對象 private var db:COpaquePointer = nil // 創建一個串行隊列 private let dbQueue = dispatch_queue_create("com.520it.lnj", DISPATCH_QUEUE_SERIAL) func execQueueSQL(action: (manager: SQLiteManager)->()) { // 1.開啟一個子線程 dispatch_async(dbQueue) { () -> Void in print(NSThread.currentThread()) // 2.執行閉包 action(manager: self) } } /** 打開數據庫 :param: SQLiteName 數據庫名稱 */ func openDB(SQLiteName: String) { // 0.拿到數據庫的路徑 let path = SQLiteName.docDir() print(path) let cPath = path.cStringUsingEncoding(NSUTF8StringEncoding)! // 1.打開數據庫 /* 1.需要打開的數據庫文件的路徑, C語言字符串 2.打開之后的數據庫對象 (指針), 以后所有的數據庫操作, 都必須要拿到這個指針才能進行相關操作 */ // open方法特點: 如果指定路徑對應的數據庫文件已經存在, 就會直接打開 // 如果指定路徑對應的數據庫文件不存在, 就會創建一個新的 if sqlite3_open(cPath, &db) != SQLITE_OK { print("打開數據庫失敗") return } // 2.創建表 if creatTable() { print("創建表成功") }else { print("創建表失敗") } } private func creatTable() -> Bool { // 1.編寫SQL語句 // 建議: 在開發中編寫SQL語句, 如果語句過長, 不要寫在一行 // 開發技巧: 在做數據庫開發時, 如果遇到錯誤, 可以先將SQL打印出來, 拷貝到PC工具中驗證之后再進行調試 let sql = "CREATE TABLE IF NOT EXISTS T_Person( \n" + "id INTEGER PRIMARY KEY AUTOINCREMENT, \n" + "name TEXT, \n" + "age INTEGER \n" + "); \n" // print(sql) // 2.執行SQL語句 return execSQL(sql) } /** 執行除查詢以外的SQL語句 :param: sql 需要執行的SQL語句 :returns: 是否執行成功 true執行成功 false執行失敗 */ func execSQL(sql: String) -> Bool { // 0.將Swift字符串轉換為C語言字符串 let cSQL = sql.cStringUsingEncoding(NSUTF8StringEncoding)! // 在SQLite3中, 除了查詢意外(創建/刪除/新增/更新)都使用同一個函數 /* 1. 已經打開的數據庫對象 2. 需要執行的SQL語句, C語言字符串 3. 執行SQL語句之后的回調, 一般傳nil 4. 是第三個參數的第一個參數, 一般傳nil 5. 錯誤信息, 一般傳nil */ if sqlite3_exec(db, cSQL, nil, nil, nil) != SQLITE_OK { return false } return true } /** 查詢所有的數據 :returns: 查詢到的字典數組 */ func execRecordSQL(sql: String) ->[[String: AnyObject]] { // 0.將Swift字符串轉換為C語言字符串 let cSQL = sql.cStringUsingEncoding(NSUTF8StringEncoding)! // 1.准備數據 // 准備: 理解為預編譯SQL語句, 檢測里面是否有錯誤等等, 它可以提供性能 /* 1.已經開打的數據庫對象 2.需要執行的SQL語句 3.需要執行的SQL語句的長度, 傳入-1系統自動計算 4.預編譯之后的句柄, 已經要想取出數據, 就需要這個句柄 5. 一般傳nil */ var stmt: COpaquePointer = nil if sqlite3_prepare_v2(db, cSQL, -1, &stmt, nil) != SQLITE_OK { print("准備失敗") } // 准備成功 var records = [[String: AnyObject]]() // 2.查詢數據 // sqlite3_step代表取出一條數據, 如果取到了數據就會返回SQLITE_ROW while sqlite3_step(stmt) == SQLITE_ROW { // 獲取一條記錄的數據 let record = recordWithStmt(stmt) // 將當前獲取到的這一條記錄添加到數組中 records.append(record) } // 返回查詢到的數據 return records } /** 獲取一條記錄的值 :param: stmt 預編譯好的SQL語句 :returns: 字典 */ private func recordWithStmt(stmt: COpaquePointer) ->[String: AnyObject] { // 2.1拿到當前這條數據所有的列 let count = sqlite3_column_count(stmt) // print(count) // 定義字典存儲查詢到的數據 var record = [String: AnyObject]() for index in 0..<count { // 2.2拿到每一列的名稱 let cName = sqlite3_column_name(stmt, index) let name = String(CString: cName, encoding: NSUTF8StringEncoding)! // print(name) // 2.3拿到每一列的類型 SQLITE_INTEGER let type = sqlite3_column_type(stmt, index) // print("name = \(name) , type = \(type)") switch type { case SQLITE_INTEGER: // 整形 let num = sqlite3_column_int64(stmt, index) record[name] = Int(num) case SQLITE_FLOAT: // 浮點型 let double = sqlite3_column_double(stmt, index) record[name] = Double(double) case SQLITE3_TEXT: // 文本類型 let cText = UnsafePointer<Int8>(sqlite3_column_text(stmt, index)) let text = NSString(CString: cText, encoding: NSUTF8StringEncoding)! record[name] = text case SQLITE_NULL: // 空類型 record[name] = NSNull() default: // 二進制類型 SQLITE_BLOB // 一般情況下, 不會往數據庫中存儲二進制數據 print("") } } return record } }
使用事務插入數據:
let manager = SQLiteManager.shareManager() // 開啟事務 manager.beginTransaction() for i in 0..<10000 { let p = Person(dict: ["name": "zs + \(i)", "age": 3 + i]) p.insertPerson() if i == 1000 { manager.rollbackTransaction() // 注意點: 回滾之后一定要跳出循環停止更新 break } } // 提交事務 manager.commitTransaction()
預編譯綁定:
//1、打開數據庫 sqlite3 *db = [self sqlite3_open_database]; //2、建立預編譯語句對象並編譯 charchar *sql = "INSERT INTO student(name,age) VALUES(?,?)";//?為占位符,代表此處將來用變量值替換 //2.1、准備預編譯語句對象 sqlite3_stmt *stmt = NULL; //2.2、預編譯sql語句 int result = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL); //2.3、預編譯成功,綁定值 if (result == SQLITE_OK) { //綁定界面數據到預編譯sql語句中 sqlite3_bind_text(stmt, 1, [self.txtName.text UTF8String], -1, NULL); sqlite3_bind_int(stmt, 2, [self.txtAge.text intValue]); //3、執行預編譯語句對象,4、使用結果 result = sqlite3_step(stmt); if (result == SQLITE_DONE) { [self myAlert:@"插入數據成功!"]; } else { [self myAlert:@"插入數據失敗!"]; } } //5、銷毀預編譯語句對象,關閉數據庫 sqlite3_finalize(stmt); sqlite3_close(db);
