Sqlite
简介
- iOS数据存数的方式
- plist(NSArray/NSDictionary) 特点:自能存储系统自带的数据类型,自定义对象无法存储
- preference(偏好设置)特点:本质就是一个Plist文件,也只能存储系统自带的数据类型,自定义对象无法存储
- NSCoding 特点可以存储自定义的数据类型,但是是一次性的全数据操作
- SQLite3 特点:存储一些大批量的数据,排序,统计操作
- Core Data 特点:对SQLite3的封装,本质上还是SQL语句执行,
- 钥匙串
SQLite
- SQLite是一款轻型的嵌入式数据库,它占用的资源非常低,在嵌入式设备中,可能只需要几百K的内存就够了,它处理的速度比Mysql这款注明的数据库还快
Swift中使用SQLite
- 创建项目,导入系统的框架sqlite3.tgb
- 需要创建桥接文件,导入头文件sqlite3.h
- 代码实现打开数据库
//sqlite数据库文件的扩展名称没有一个标准,一般流行都是以sqlite,db,db3命名 var db :COpaquePointer = nil func openDataBase(){ let filename = "/Users/dingkan/Desktop" + "/demo.sqlite" //sqlite3_open方法用来创建打开一个数据库 //参数一:sqlite数据库的路径 //参数二: 一个指向SQLite3的数据的结构指针,到时候操作数据库都需要用到这个对象 //作用:通过一个路径来创建数据库,如果路径处存在数据域,那么久打开该数据库,如果不存在就创建一个数据库 if sqlite3_open(filename, &db) != SQLITE_OK { print("数据库创建失败") }else{ print("数据库创建成功") } }
DDL语句
- 1.创建一个数据库表
func creatTable(){ //创建sqlite语句 let sql = "CREATE TABLE if not exists t_Student(id integer PRIMARY KEY AUTOINCREMENT,name text not NULL, age integer default 18, source integer)" //参数一: 一个打开的数据库 //参数二: sql语句 //参数三:回调结果,执行完毕后回调的函数,如果不需要可以传nil //参数4:参数三的第一个参数,可以通过这个参数传值给回调的函数,如果不需要就传nil //参数5:错误信息 if sqlite3_exec(db, sql, nil, nil, nil) == SQLITE_OK { print("列表创建成功") }else{ print("列表创建失败") }
- 2.删除数据库表
//删除表格 func dropTable(){ let sql = "drop table if exists t_Student" if exec(sql){ print("删除成功") }else{ print("删除失败") } }
- 3.修改数据库表
func alterTable(){ let sql = "alter table t_Student add column name text" if exec(sql){ print("添加成功") }else{ print("添加失败") } } //抽取 func exec(sql: String) ->Bool{ return sqlite3_exec(db, sql, nil, nil, nil) == SQLITE_OK }
DML语句
-
1.插入数据
-sqlit语句格式:insert into 表名(字段1,字段2...) values(字段1的值,字段2的值...);
-利用代码来插入数据func insert()->Bool{ let sql = "insert into t_Student(name, age, source) values('\(name)' , \(age),\(source))" return Tool.shareInstance.exec(sql) }
-
2.更新数据
- sqlite语句格式:update 表名 set 字段1 = 字段1的值, 字段2 = 字段2的值...;
- 利用代码来实现更新数据
class func update(stu:DKStudent)->Bool{ let sql = "update t_Student set name='\(stu.name)',age = \(stu.age), source = \(stu.source)" return Tool.shareInstance.exec(sql) }
-
3.删除数据
- sqlite语句格式: delete from 表名 Where 字段1 = 字段1的值...;
- 利用代码来实现删除数据
func delete()->Bool{ let sql = "delete from t_Student where name = '\(name)'" return Tool.shareInstance.exec(sql) }
-
Insert绑定参数
-
准备语句(prepared tatement)对象,准备语句对象,代表了一个简单的SQL语句对象的实例,这个对象通常被称作
准备语句
获取编译好的SQL语句
-
操作过程
- 1.创建准备语句对象,如果执行成功,则返回SQLITE_OK,否则返回一个错误码
- 1.创建准备语句对象,如果执行成功,则返回SQLITE_OK,否则返回一个错误码
//1.固定写法
let sql = "insert into t_Student(name, age, source) values(?, ?, ?)"
//2.创建准备语句
let db = Tool.shareInstance.db
参数一: 数据库
参数二: sql语句
参数三: 代表从sql字符串中取出的长度, -1代表自动计算
参数四: 代表准备语句地址
参数五: 按照参数三从参数二中取出字符串剩下的字符串
//创建一个空的准备语句,获取返回的结果
var stmt : COpaquePointer = nil
if sqlite3_prepare_v2(db, sql, -1, &stmt, nil) != SQLITE_OK{
print("编译失败")
return
}
- 2.绑定参数
```
// 绑定参数
//参数一: 准备语句
//参数二: 绑定的参数索引(从1开始)
//参数三: 绑定的参数的内容
//参数四: 绑定参数的长度 -1代表自动计算
//参数五: 参数的处理方式
// #define SQLITE_STATIC 会对字符串做一个copy,SQLite选择合适的机会释放
//#define SQLITE_TRANSIENT 会当做全局静态变量,不会对字符串做任何处理,如果字符串被释放,保存到数据库的内容可能不正确
//swift中没有宏的概念,所以需要替换
let SQLITE_TRANSIENT = unsafeBitCast(-1, sqlite3_destructor_type.self)
sqlite3_bind_text(stmt, 1,"aa", -1, SQLITE_TRANSIENT)
sqlite3_bind_int(stmt, 2, 13)
sqlite3_bind_double(stmt, 3, 80.0)
```
- 3.执行sql
```
//对于DML语句,如果执行成功,则返回SQLITE_DONE,
//对于DQL语句,通过多次执行获取结果集,继续执行的条件是SQLITE_ROW
if sqlite3_step(stmt) != SQLITE_DONE{
print("执行失败")
return
}
```
- 4.重置语句
```
sqlite3_reset(stmt)//使用sqlite3_reset()重置这个语句,让后回到上一步,绑定参数,这个过程可能做0次,也可能左多次
```
- 5.销毁对象,防止内存泄露
```
sqlite3_finalize()
```
#####Transaction事务
- 事务是并发控制的单位,是用户定义的一个操作序列,这个操作要么做,要么都不做,是一个不可分割的工作单位,通过事务,可以将逻辑相关的一些操作绑定在一起,保证数据的完整性
-使用事务来优化
- 大批量数据插入的优化
- 第一层优化: 使用`准备语句`
- 第二层优化: 无论是sqlite3_exec,还是sqlite3_step,都会在内容自动`开启事务`,自动`提交事务`,一旦自动开启,自动提交,就会非常的耗时,
- 解决方案: 只要我们手动开启,和手动提交,那么系统就不会来自动执行,
######DQL语句
- 代码实现DQL语句的方式
- 方式一: 利用sqlite3_exec来实现,作用: 可以通过回调来获取结果,步骤相对简单,结果数据类型没有特定类型(id)
```
func queryALl(){
//方式一: 通过sqlite_exec来查询
//sql语句
let sql = "select * from t_Student"
let db = Tool.shareInstance.db
//参数一:可以打开的数据库
//参数二:需要执行的SQL语句
//参数三 查询结果回调
//参数1: 参数4的值
//参数2: 列的个数
//参数3: 结果值的数组
//参数4: 所有列的名称数组
//返回值为0 表示继续查询,返回值非0 表示终止查询
//参数四:回调函数的第一个参数
//参数五:错误信息
sqlite3_exec(db, sql, { (firsPara, columnCount, values, columnNames) -> Int32 in
//将UnsafeMutablePointer<Int8>转换成int类型
let count = Int(columnCount)
for i in 0..<count{
//取出每一列的名称和对应的值
let valueC = values[i]
let value = String(CString: valueC, encoding: NSUTF8StringEncoding)
//需要转换成字符串类型
let nameC = columnNames[i]
let name = String(CString: nameC, encoding: NSUTF8StringEncoding)
print(value, name)
}
return 1//0表示继续查询,非0表示终止插叙
}, nil, nil)
}
```
- 方式二:通过准备语句来实现,可处理不同特定类型
```
class func queryAllStmt() {
let sql = "select * from t_Student"
// 1. 创建一个准备语句
let db = SQLiteTool.shareInstance.db
var stmt: COpaquePointer = nil
if sqlite3_prepare_v2(db, sql, -1, &stmt, nil) != SQLITE_OK {
print("预处理失败")
return
}
// 2. 绑定参数(可以省略)
// 3. 执行,如果下一行没有内容就不会执行
while sqlite3_step(stmt) == SQLITE_ROW {
// 1. 确定有多少列
let count = sqlite3_column_count(stmt)
// 2. 遍历所有的列
for i in 0..<count {
// 3. 取出列名, 列对应的值
let columnName = sqlite3_column_name(stmt, i)
let columnNameStr = String(CString: columnName, encoding: NSUTF8StringEncoding)
print(columnNameStr)
// 应该根据列对应的类型, 使用不同的函数, 来取出不同的值
let type = sqlite3_column_type(stmt, i)
// 2. 根据不同的类型, 使用不同的函数, 取出不同的值!
if type == SQLITE_INTEGER {
let value = sqlite3_column_int(stmt, i)
print(value)
}
if type == SQLITE_FLOAT {
let value = sqlite3_column_double(stmt, i)
print(value)
}
if type == SQLITE3_TEXT {
let value = UnsafePointer<CChar>(sqlite3_column_text(stmt, i))
let valueStr = String(CString: value, encoding: NSUTF8StringEncoding)
print(valueStr)
}
}
}
// 4. 重置(可以省略)
// 5. 释放资源
sqlite3_finalize(stmt)
}
```
网友评论