有一些基本的概念学习了下就是
SQLite的框架是纯C语言的框架
所有函数都是以 sqlite_开头的
SQLite操作是持久化的连接,在整个过程中我们不需要管理数据库的连接,先打开,使用完毕之后,我们再通过sqlite3_close()关闭就可以了。
什么是持久化连接,就是一直的去占用这个数据库的资源,就好比我们在网络中的持久化连接,即时通讯的过程应该就是持久化连接的。不然的话一下子断一下,一下子断一下,接受消息就有可能在某个时间段接受不到,之后才接受的到。
sqlite3_open(path,&dataBase),
参数1:数据库的全路径,Int8 对应的是一个字节,数据库的全路径是C语言的字符串,在Swift中我们可以用String来传递
此函数如果数据库不存在的话,就会创建数据库,然后再打开
如果已经存在的,就直接打开数据库
打开数据库的这个函数的第二个参数是需要一个OpaquePointer的类型的对象的地址
这个类型就是不透明的类型,为什么说是不透明的类型,因为因为在C语言中没有对象的概念,只有结构体,然后结构体里面有什么也是无法得知的所有
var dataBase: OpaquePointer? = nil
执行SQL语句的函数
参数
1、数据库的全局句柄用来操作数据库
2、要执行的SQL语句
3、callback 是执行完SQL之后,调用的C语言函数指针,通常传入nil
4、第三个参数 callBack 是函数参数的地址,通常传入nil
5、错误信息,我们可以在通过char *error = NULL 然后传入&error,当然也可以传入nil
返回值,如果是SQLITE_OK 就表示成功
sqlite3_exec(db, sql, nil, nil, nil) == SQLITE_OK
下面是SWift中SQL语句的编写
let sql = "CREATE TABLE 'T_Person'(" +
"'id' INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT," +
"'name' TEXT," +
"'age' INTEGER," +
"'height' REAL" +
");"
我们在调试的时候,方便我们查看,可以在拼接字符串的时候,往后面添加一个\n,这样我们就方便查看了,输出的时候都有换行
let sql = "CREATE TABLE 'T_Person'(\n" +
"'id' INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,\n" +
"'name' TEXT,\n" +
"'age' INTEGER,\n" +
"'height' REAL\n" +
");"
由于用上面的利用字符串来构造表的方式太过繁琐,就比如说我们要建立100个文件,这样建立会显得很麻烦,所以我们可以通过创建一个空的文件,然后再这个空的文件中写入,我们要创建表的SQL语句,然后我们再进行读取。其中exexSQL函数是我们自己定义的
//执行SQL指令
func execSQL(sql:String) -> Bool
{
/**
参数
1、数据库的全局句柄用来操作数据库
2、要执行的SQL语句
3、callback 是执行完SQL之后,调用的C语言函数指针,通常传入nil
4、第三个参数 callBack 是函数参数的地址,通常传入nil
5、错误信息,我们可以在通过char *error = NULL 然后传入&error,当然也可以传入nil
返回值,如果是SQLITE_OK 就表示成功
*/
return sqlite3_exec(db, sql, nil, nil, nil) == SQLITE_OK
}
//MARK: 创建多个表,我们可以在一个文件中进行写入SQL语句,然后再读取再进行创建
private func creatTable1() -> Bool
{
//1、从bundle中加载sql文件
let path = Bundle.main.path(forResource: "information.sql", ofType: nil)!
//读取SQL字符串
let sql = try! String(contentsOfFile:path)
return exexSQL(sql: sql)
}
使用sqlite3来进行查询数据的话,我们可以通过调用sqlite3_prepare_v2来获取预编译的结果stmt,然后再通过sqlite3_step(stmt)来一个一个的取每一个数据。
具体步骤其实就是这样,先获取SQL预编译的句柄
func execRecordSet(sql:String)
{
//1、预编译 SQL
/**
参数1、全局数据库的句柄
参数2、要执行的SQL的C语言字符串
参数3、要执行的SQL的以字节为单位的长度,如果我们传入-1,SQLite框架会自动计算
参数4、stmt- 就是预编译的指令句柄
后续我们针对本地查询的所有的操作,全部是基于此句柄的
我们需要注意的是,句柄一定要释放
编译完成之后,我们其实可以把这个句柄理解成一个临时的数据的集合,通过step函数
我们能够顺序的取得其中的结果,其实就是使用C语言字符串来获得sql准备语句(prepared statement),然后转化为可被SQLite3识别的执行语句
参数5、关于stmt尾部参数的指针,通常会传入nil
返回值,如果编译成功了,就表示SQL能正常的执行,返回SQLITE_OK
sqlite3_prepare和sqlite3_perpare_v2的区别在于前面的函数是向前兼容的,有v2的推荐给新程序使用
*/
var stmt:OpaquePointer?
if sqlite3_prepare_v2(db, sql, -1, &stmt, nil) != SQLITE_OK
{
print("SQL错误")
//释放句柄
sqlite3_finalize(stmt)
}
print("SQL正确")
//释放句柄
sqlite3_finalize(stmt)
}
遍历每一条记录,从stmt中取,这里用while循环是因为sqlite3_step是一条一条记录去取的,如果取到了就会返回SQLITE_ROW
while sqlite3_step(stmt) == SQLITE_ROW
{
//1、知道记录的列数
let columns = sqlite3_column_count(stmt)
//循环每一列,获得每一列对应的内容
for colu in 0..<columns
{
//1、获取相应的列名 Int8 /CChar /Byte是一样的
let cname = sqlite3_column_name(stmt,colu)
//根据C语言字符串转换成Swift中的String字符串
let name = String(cString: cname!, encoding:String.Encoding.utf8)
//2、获取数据的类型
let type = sqlite3_column_type(stmt, colu)
var value:AnyObject?
switch type
{
//小数
case SQLITE_FLOAT:
value = sqlite3_column_double(stmt, colu) as AnyObject
//整数
case SQLITE_INTEGER:
value = Int(sqlite3_column_int(stmt, colu)) as AnyObject
//字符串
case SQLITE3_TEXT:
let cText = sqlite3_column_text(stmt, colu)
value = String(cString: cText!) as AnyObject
//空值,数据库允许字段为空
case SQLITE_NULL:
value = NSNull()
default:
print("不支持的数据类型")
}
print(value)
}
}