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);
时间: 2024-10-12 15:11:36