SQLite3数据库
目录
SQL语言的简介
什么是SQL
SQL(structured query language 全名叫 结构化查询语言)是一种对关系型数据库中的数据进行定义和操作的语言
SQL语言分为三种语句
- 数据定义语句(DDL)
- 是用来对SQL数据库进行操作(在数据库中创建新表 删除表 和 修改表(create table drop table 和 alter table))
- 数据操作语句(DML)
- 是用来对数据库里面的表来进行操作(包括insert、delete、update操作分别添加 修改 和 删除)
- 数据查询语句(DQL)
- 是专门用来对数据库表进行查询的(关键字select是DQL(也是所有SQL)用得最多的操作,其他DQL常用的关键字有where,order by,group by和having)
SQL有图形化工具(这里就不介绍)
SQL在代码中的操作
- 首先要导入系统框架sqlite3.tbd(sqlite3.dylib)
注意在下面会使用到的3个值,在此先说明
对于DDL语句, 如果执行成功, 返回SQLITE_OK
对于DML语句, 如果执行成功, 返回SQLITE_DONE
对于DQL语句, 通过多次执行获取结果集, 继续执行的条件是返回值 SQLITE_ROW
DDL语句
- 执行函数(重要的函数,每个sql语句要执行都要调用这个函数,if语句是为了做校验)
if sqlite3_exec(db, sql, nil, nil, nil) != SQLITE_OK {
print("创建表失败")
return
}else {
print("成功")
}
- 创建一个打开的数据库( sqlite数据库文件的后缀名规范: sqlite, db, db3)
- 注意打开数据库有2个函数
区别:sqlite3_open_v2的函数要比sqlite3_open性能好,但是sqlite3_open_v2如果没有数据库就会打开失败
sqlite3_open函数如果没有数据库,它会创建一个数据库
sqlite3_open_v2()
sqlite3_open()
// 创建并且打开一个数据库
// 根据路径打开一个而数据库, 如果数据库路径不存在, 就创建, 如果存在, 直接打开
// UTF8编码
// 参数1: 数据库文件的路径
// 参数2: 一个已经打开的数据库(一定要知道, 如果后面, 想要执行sql语句, 必须使用这个对象, 才能执行, 否则无法执行)
let path = "/Users/xmg/Desktop/db/" + "demo.sqlite"
if sqlite3_open(path, &db) != SQLITE_OK {
print("数据库打开失败")
return
}else {
print("数据库打开成功")
}
创建一个数据库表
// 操作数据库, 只能通过sql语句
// 1. 写好对应的sql字符串
let sql = “create table if not exists t_stu(id integer primary key autoincrement, name text not null, age integer default 18, score real default 60.0)”
// 2. 执行sql语句
// 参数1: 就是一个已经打开的数据库
// 参数2: sql字符串
// 参数3: 回调代码块 nil
// 参数4: 参数3 中的参数1 nil
// 参数5: 错误信息
if sqlite3_exec(db, sql, nil, nil, nil) != SQLITE_OK {
print(“创建表失败”)
return
}else {
print(“成功”)
}删除一个数据库表
func dropTable() -> () {
// 1. 写sql语句
let sql = "drop table if exists t_stu"
// 2. 执行
if sqlite3_exec(db, sql, nil, nil, nil) != SQLITE_OK {
print("删除表失败")
return
}else {
print("成功")
}
- 修改一个数据库表
func alterTable() -> () {
// 1. 写sql语句
let sql = "alter table t_stu add column address text"
// 2. 执行
if sqlite3_exec(db, sql, nil, nil, nil) != SQLITE_OK {
print("修改表失败")
return
}else {
print("成功")
}
}
DML语句
- 最基本的方式(与DDL语句一直)
- 主要点 在写文本时要打单引号
//先写sql语句 在写执行代码
//创建表
let sql = "insert into t_stu(name, age, score) values ('\(name)', \(age), \(score))"
//删除指定的表
let sql = "delete from t_stu where name = '\(name)'"
//修改表内容
let sql = "update t_stu set name = '\(newStu.name)', age = \(newStu.age), score = \(newStu.score)"
//执行函数
if sqlite3_exec(db, sql, nil, nil, nil) != SQLITE_OK {
print("创建表失败")
return
}else {
print("成功")
}
第二种方式(绑定参数)(是把sqlite3_exec(db, sql, nil, nil, nil)这个函数的拆分,也就是sqlite3_exec(db, sql, nil, nil, nil)内部就是绑定参数)
- 写sql语句(一般插入用绑定参数,写法也是
let sql = "insert into t_stu(name, age, score) values (?, ?, ?)"
- 使用sqlite3_bind_v2或相关的函数创建对象
// 1. 创建准备语句 // 功能作用: 创建编译一个sql字符串,-> sql准备语句 // 参数1: 一个已经打开的数据库 // 参数2: sql 字符串 // 参数3: 代表从sql字符串里面取出的长度 -1, 代表自动计算 // 参数4: "准备语句" 地址 !!!!!!!!! // 参数5: 按照参数3, 给定的长度, 到参数2, 里面取出的字符串, 剩下的字符串 let db = SQLiteTool.shareInstance.db//(自己写的工具类方法获取数据库) var stmt: COpaquePointer = nil(这个是用来取地址) if sqlite3_prepare_v2(db, sql, -1, &stmt, nil) != SQLITE_OK { print("编译失败") return }
- 使用sqlite3_bind_*()给宿主参数(host parameters)绑定值
// 绑定值有不同的类型 // 参数1: 准备语句 // 参数2: 绑定的索引(索引, 从1开始) // 参数3: 绑定的值 sqlite3_bind_int(stmt, 2, 16) sqlite3_bind_double(stmt, 3, 99) //特别注意文本类型绑定的值 // 参数4: 代表参数三取出多少长度 -1自动计算 // 参数5: 代表, 参数的处理方式(这个计算方式在oc中用宏代替) 处理方式: SQLITE_STATIC ((sqlite3_destructor_type)0) // 代表, 把参数当做一个静态的值, 不会被释放(内部处理, 不对参数做任何的引用) SQLITE_TRANSIENT ((sqlite3_destructor_type)-1) // 代表, 把参数当做是一个临时的值, 有可能会被释放, (内部处理, 对参数做一次引用, 然后, 在合适的地方, 释放掉) 注意:在swift中没有宏的概念所以要转换 swift中提供了一个方法unsafeBitCast() // 不安全的按位进行转换 // 一定要注意,必须明确的确定, 最终的值是什么类型,才能进行转换 // 否则,崩溃! // 参数1: 需要转换的额值 // 参数2: 代表, 想要转换成为的类型 let SQLITE_TRANSIENT = unsafeBitCast(-1, sqlite3_destructor_type.self) sqlite3_bind_text(stmt, 1, "王二小", -1, SQLITE_TRANSIENT)
- 通过调用sqlite3_step() 一次或多次来执行这个sql
if sqlite3_step(stmt) != SQLITE_DONE { print("执行失败") return }
- 使用sqlite3_reset()重置这个语句,然后回到第2步,这个过程做0次或多次
// 把绑定的值, 清空 sqlite3_reset(stmt)
- 使用sqlite3_finalize()销毁这个对象, 防止内存泄露
sqlite3_finalize(stmt)
DQL语句
“`
// 1. sql语句
let sql = “select * from t_stu”
// 2. 执行语句
// 参数1: 一个已经打开的数据库
// 参数2: sql语句
// 参数3: 回调代码(*) 当查询到结果之后, 会调用这个代码块, 把结果返回给我们
// 参数1: 参数4
// 参数2: 列的个数
// 参数3: 值组成的数组
// 参数4: 列名组成的数组
// 返回值: 如果返回的是 0 继续查询, 非0 代表停止查询
// 参数4: 参数3里面的参数1
// 参数5: 错误信息
let db = SQLiteTool.shareInstance.db
sqlite3_exec(db, sql, { (firsPara, columnCount, values, columnNames) -> Int32 in
// 操作的是一行, 一行记录
// 包含了很多个列
// 遍历这些列(列名称, 列对应的值)
let count = Int(columnCount)
for i in 0..<count {
// 代表每一列
// (列名称, 列对应的值)
// UnsafeMutablePointer<Int8>
let columnName = columnNames[i]
let columnNameStr = String(CString: columnName, encoding: NSUTF8StringEncoding)
// UnsafeMutablePointer<Int8>
let value = values[i]
let valueStr = String(CString: value, encoding: NSUTF8StringEncoding)
print(columnNameStr, valueStr)
}
return 2
}, nil, nil)
“`
这就是sql的代码基本操作! 有关优化问题后面再介绍!!