let path = Bundle.main.path(forResource: "test", ofType: ".db")
print(path!)
let db = try! Connection(path!)
try! db.execute("create table t_teacher(name text, email text)")
数据库框架构建无非是,将原本SQL语句和对应操作的数据对象进行绑定管理,封装成增、删、改、查的操作接口便于用户调用。
自己构建过程中,为了验证操作数据我们需要一个查看数据库的工具。
功能:打开数据库,关闭数据库,执行SQL语句,数据库基本属性使用
三种数据库存储位置不同
三种类型:内存数据库、临时数据库、URI方式(地址)
定义枚举=>Location
public enum Location {
//内存数据库->相当于->uri(":memory")
case inMemory
//临时数据库->相当于->uri("")
case temporary
//URI方式(地址)->相当于->uri("/user/test.db")
case uri(String)
}
种类:
插入数据-insert
更新数据-update
删除数据-delete
枚举=>定义表操作
public enum Operation {
// 插入数据-insert
case insert
// 更新数据-update
case update
// 删除数据-delete
case delete
//数据库类型转换
fileprivate init(rawValue:Int32){
switch rawValue {
case SQLITE_INSERT:
self = .insert
case SQLITE_UPDATE:
self = .update
case SQLITE_DELETE:
self = .delete
default:
fatalError("没有这个操作类型...")
}
}
}
通过构造方法实现
fileprivate var _handle: OpaquePointer? = nil
public init(_ location: Location = .inMemory, readonly: Bool = false) throws {
//打开数据库
//参数一:数据位置
//参数二:数据库指针(用于操作数据库)
//参数三:打开数据库方式
//SQLITE_OPEN_READONLY:只读数据库
//SQLITE_OPEN_CREATE:创建数据库(没有就创建)
//SQLITE_OPEN_READWRITE:可读可写数据库
//SQLITE_OPEN_FULLMUTEX:设置数据库链接运行队列模式->串行队列、并行队列
//支持多线程操作
let flags = readonly ? SQLITE_OPEN_READONLY : SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE
let result = sqlite3_open_v2(location.description, &_handle, flags | SQLITE_OPEN_FULLMUTEX, nil)
//判定数据库是否成功状态(面向形式设计)
//将result->变为对象->枚举->关心可选项
//关心 = 1,0,-1->枚举->对象->代码阅读可读性高
//检测数据库返回值
try check(result)
//第六步:定义队列->并行队列
//主队列:串行队列
//设置队列值(缓存当前Connaction所在的队列)
queue.setSpecific(key: queueKey, value: queueContext)
}
//普及一个语法->遍历构造器
public convenience init(_ filename: String, readonly: Bool = false) throws {
try self.init(.uri(filename), readonly: readonly)
}
定义Result枚举类,泛型枚举
public enum Result : Error {
//SQLITE_OK->执行成功
//SQLITE_ROW->执行下一行(成功)
//SQLITE_DONE->执行完成
fileprivate static let successCodes: Set = [SQLITE_OK, SQLITE_ROW, SQLITE_DONE]
case error(message: String, code: Int32)
//errorCode->数据库返回结果
init?(errorCode: Int32, connection: Connection){
guard !Result.successCodes.contains(errorCode) else {
return nil
}
//获取错误信息(封装数据库错误信息)
let message = String(cString: sqlite3_errmsg(connection._handle))
//初始化error信息
self = .error(message: message, code: errorCode)
}
}
定义检测方法check()
//检测是否成功,还是失败
//resultCode->数据库返回结果
//throws->向外抛异常->客户端处理异常
//大家都是用代码,很少自己写(成长很少)
//第一次接触,蒙蔽很正常
//相当于异常传递->事件传递
@discardableResult func check(_ resultCode: Int32) throws -> Int32 {
guard let error = Result(errorCode: resultCode, connection: self) else {
return resultCode
}
//失败了->数据库打开失败了
//抛异常(我不处理异常)
throw error
}
数据库所有表操作改在什么样队列中执行?樂
串行队列=>单窗口一个个排队执行(线下买票)
串行队列定义:DispatchQueue(label: "database")
并行队列=>同时执行(网上购票)
并行队列定义(加了一个attributes):DispatchQueue(label: "database", attributes: [])
定义处理队列
//定义并行队列参数queue,queueKey
fileprivate var queue = DispatchQueue(label: "database", attributes: [])
//根据key获取值
fileprivate var queueKey = DispatchSpecificKey<Int>()
//当前Connection指针->将Connection类对象引用->转为Int类型指针(引用)->强制类型转换
//根据这个指针判定当前是串行队列,还是并行队列
fileprivate lazy var queueContext: Int = unsafeBitCast(self, to: Int.self)
func sync<T>(_ block: () throws -> T) rethrows -> T {
//定义队列
if DispatchQueue.getSpecific(key: queueKey) == queueContext {
//串行队列->直接执行->主队列->排队执行
return try block()
} else {
//并行队列->子队列->指通过queue管理执行,同时执行
return try queue.sync(execute: block)
}
}
并在第一个构造函数里检测完调用(第四部)
//第六步:定义队列->并行队列
//主队列:串行队列
//设置队列值(缓存当前Connaction所在的队列)
queue.setSpecific(key: queueKey, value: queueContext)
func execute(_ SQL: String) throws {
//同步代码块
//"_"表示返回变量名接受"_"默认->变量通配符->没有类型
_ = try sync {
try self.check(sqlite3_exec(self._handle, SQL, nil, nil, nil))
}
}
deinit {
//析构函数
sqlite3_close(_handle)
}
public var readonly: Bool {
return sqlite3_db_readonly(_handle, nil) == 1
}
public var lastInsertRowId: Int64 {
return sqlite3_last_insert_rowid(_handle)
}
public var changes: Int {
return Int(sqlite3_changes(_handle))
}
// insert、delete、update总共操作几次
// insert->10次(插入10条数据)
// delete->删除5条->干坏事5次
// update->更新2次->干坏事2次
// 总共:到目前为止17次
public var totalChanges: Int {
return Int(sqlite3_total_changes(_handle))
}
// 服务器开发->我开发服务器->100万数量级->耗费时间长
public func interrupt(){
sqlite3_interrupt(_handle)
}
public var busyTimeout: Double = 0 {
didSet{
sqlite3_busy_timeout(_handle, Int32(busyTimeout * 1_000))
}
}
SQliteFramework
面向对象编程,创建表SQL let users = Table("users")
let name = Expression<String>("name")
let email = Expression<String>("email")
let sql = users.create { (t) in
t.column(name).column(email)
}