SQLite.swift對SQLite進行了全面的封裝栅干。作者采用了鏈?zhǔn)骄幊痰膶懛ǎ寯?shù)據(jù)庫的管理變得優(yōu)雅梆暮,可讀性也很強猜拾。下面就說說如何使用
創(chuàng)建數(shù)據(jù)庫
private init() {
// 獲取保存數(shù)據(jù)庫的路徑
let path = getDocumentsPath()
let dataPath = "\(path)/dataDB.sqlite3"
do {
// 初始化方法府适,第一個參數(shù)Location指的是數(shù)據(jù)庫的位置,有下面3種入?yún)?// database = try Connection(.inMemory)//數(shù)據(jù)庫存在內(nèi)存里
// database = try Connection(.temporary)//臨時數(shù)據(jù)庫肺樟,使用完會被釋放掉
// 存在硬盤中
database = try Connection(dataPath)
database?.userVersion = 1 //數(shù)據(jù)庫版本
database?.busyTimeout = 5 //嘗試重新連接語句的時間
// 也是嘗試重新連接語句安全設(shè)置檐春,跟busyTimeout2選1即可
// database?.busyHandler({ tries in
// if tries >= 5 {
// return false
// }
// return true
// })
} catch _ {
database = nil
}
}
創(chuàng)建表
static func createTable() throws {
guard let DB = BaseDBModel.sharedInstance.database else {
throw DataAccessError.datastoreConnectionError
}
do {
// ifNotExists:是否不存在的情況才會創(chuàng)建,記得設(shè)置為true
// withoutRowid: 是否自動創(chuàng)建自增的rowid
_ = try DB.run(table.create(ifNotExists: true, withoutRowid: false, block: { t in
t.column(name)
t.column(age)
}))
print("測試表 創(chuàng)建成功")
} catch _ {
print("測試表 創(chuàng)建失敗")
throw DataAccessError.datastoreConnectionError
}
}
插入數(shù)據(jù)
static func insertWithData (array: Array<[String: Any]>) throws -> Void {
guard let DB = BaseDBModel.sharedInstance.database else {
throw DataAccessError.datastoreConnectionError
}
for dic in array {
let insert = table.insert(name <- isNonEmpStrAny(dic["name"]), age <- isNonEmpStrAny(dic["age"]))
do {
let rowId = try DB.run(insert)
guard rowId >= 0 else {
print("插入失敗")
throw DataAccessError.insertError
}
print("插入成功:\(rowId)")
} catch {
print(error)
print("插入失斆床疟暖!")
throw DataAccessError.insertError
}
}
}
查詢所有數(shù)據(jù)
static func seleAllData () throws -> Array<[String : Any]> {
guard let DB = BaseDBModel.sharedInstance.database else {
throw DataAccessError.datastoreConnectionError
}
var array: [[String : Any]] = []
let items = try DB.prepare(table)
for item in items {
let dic = ["name" : item[name], "age" : item[age]]
array.append(dic)
}
return array
}
修改數(shù)據(jù)
/// 根據(jù)age修改name
static func changeDataWith(modName: String,queryAge: String) throws -> Bool {
guard let DB = BaseDBModel.sharedInstance.database else {
throw DataAccessError.datastoreConnectionError
}
let query = table.filter(age == queryAge)
if try DB.run(query.update(name <- modName)) > 0 {
return true
} else {
throw DataAccessError.upDataError
}
}
刪除所有數(shù)據(jù)
static func deleteAllData () throws -> Void {
guard let DB = BaseDBModel.sharedInstance.database else {
throw DataAccessError.datastoreConnectionError
}
if let count = try? DB.run(table.delete()) {
print("刪除的條數(shù)為:\(count)")
} else {
print("刪除失敗")
throw DataAccessError.deleteError
}
}
實際使用
// 插入數(shù)據(jù)
try? TestDBModel.insertWithData(array: array)
let resultArray1: [[String : Any]] = try! TestDBModel.seleAllData()
printLog("第一次查詢結(jié)果" + String(resultArray1.count))
for dic in resultArray1 {
printLog("name : " + (dic["name"] as! String) + ", age : " + (dic["age"] as! String))
}
// 把age為20的數(shù)據(jù)name改成王五
let _ = try? TestDBModel.changeDataWith(modName: "王五", queryAge: "20")
let resultArray2: [[String : Any]] = try! TestDBModel.seleAllData()
printLog("第二次查詢結(jié)果" + String(resultArray2.count))
for dic in resultArray2 {
printLog("name : " + (dic["name"] as! String) + ", age : " + (dic["age"] as! String))
}
// 刪除數(shù)據(jù)
try? TestDBModel.deleteAllData()
let resultArray3: [[String : Any]] = try! TestDBModel.seleAllData()
printLog("第三次查詢結(jié)果" + String(resultArray3.count))
輸出結(jié)果:
2023-04-27 14:03:03.603: 第一次查詢結(jié)果2
2023-04-27 14:03:03.603: name : 張三, age : 20
2023-04-27 14:03:03.604: name : 李四, age : 21
2023-04-27 14:03:03.606: 第二次查詢結(jié)果2
2023-04-27 14:03:03.606: name : 王五, age : 20
2023-04-27 14:03:03.607: name : 李四, age : 21
2023-04-27 14:03:03.608: 第三次查詢結(jié)果0
可以發(fā)現(xiàn)增、刪田柔、改俐巴、查都達到了預(yù)期結(jié)果
主鍵
創(chuàng)建表的時候設(shè)置
_ = try DB.run(table.create(ifNotExists: true, withoutRowid: false, block: { t in
t.column(name, primaryKey: true)
t.column(age)
}))
let array = [["name" : "張三", "age" : "20"], ["name" : "李四", "age" : "21"], ["name" : "李四", "age" : "22"]]
// 插入數(shù)據(jù)
try? TestDBModel.insertWithData(array: array)
let resultArray1: [[String : Any]] = try! TestDBModel.seleAllData()
printLog("第一次查詢結(jié)果" + String(resultArray1.count))
for dic in resultArray1 {
printLog("name : " + (dic["name"] as! String) + ", age : " + (dic["age"] as! String))
}
輸出結(jié)果:
2023-04-27 14:15:30.710: 第一次查詢結(jié)果2
2023-04-27 14:15:30.710: name : 張三, age : 20
2023-04-27 14:15:30.710: name : 李四, age : 21
我們可以發(fā)現(xiàn)["name" : "李四", "age" : "22"]這條數(shù)據(jù)沒有存到庫中,也就是主鍵起了作用
聯(lián)合主鍵
_ = try DB.run(table.create(ifNotExists: true, withoutRowid: false, block: { t in
t.column(name)
t.column(age)
t.primaryKey(name, age)
}))
let array = [["name" : "張三", "age" : "20"], ["name" : "李四", "age" : "21"], ["name" : "李四", "age" : "22"], ["name" : "李四", "age" : "22"], ["name" : "張三", "age" : "21"]]
// 插入數(shù)據(jù)
try? TestDBModel.insertWithData(array: array)
let resultArray1: [[String : Any]] = try! TestDBModel.seleAllData()
printLog("第一次查詢結(jié)果" + String(resultArray1.count))
for dic in resultArray1 {
printLog("name : " + (dic["name"] as! String) + ", age : " + (dic["age"] as! String))
}
輸出結(jié)果:
2023-04-27 14:23:20.862: 第一次查詢結(jié)果4
2023-04-27 14:23:20.862: name : 張三, age : 20
2023-04-27 14:23:20.863: name : 李四, age : 21
2023-04-27 14:23:20.863: name : 李四, age : 22
2023-04-27 14:23:20.863: name : 張三, age : 21
可以發(fā)現(xiàn)["name" : "李四", "age" : "22"]這條數(shù)據(jù)沒有存到庫中硬爆,也就是聯(lián)合主鍵起了作用
另:暫時還沒有發(fā)現(xiàn)如何修改主鍵欣舵,也就是表已經(jīng)創(chuàng)建好了,name是主鍵缀磕,過了幾天發(fā)現(xiàn)要用age當(dāng)主鍵缘圈。是不支持還是沒找到方法,有大神知道可以評論袜蚕。
新增字段
開發(fā)中糟把,有時候我們需要在表中新增列,可以使用如下方法廷没,新增需要的列
var isExist = false
// 獲取該表所有的字段名稱
let expression = table.expression
let colunmnNames = try DB.prepare(expression.template,expression.bindings).columnNames
for colName in colunmnNames {
print(colName)
// 判斷新增的字段名稱是否存在
if colName == "achievement" {
isExist = true
break
}
}
// 不存在則添加
if !isExist {
try DB.run(table.addColumn(achievement, defaultValue: ""))
}
這樣在這張表里面就新增achievement列成功了糊饱。
查詢
多條件查詢
let query = table.filter(age == "20").filter(achievement == "66")
let items = try DB.prepare(query)
// select(name) //只查詢name字段
// limit(2, offset: 1) // 分頁
// group(achievement) //分組
// order(achievement .asc) //排序
prepare垂寥、run颠黎、scalar使用條件
run 適用于 delete、insert滞项、update 等
scalar 適用于 exists(是否存在)狭归、count(總數(shù)量)等ScalarQuery類型返回值的
prepare 適用于其他QueryType類型返回值的
SQL語句查詢,直接寫好語句用run或者prepare文判。用scalar查詢也可以过椎,但是只會返回第一條數(shù)據(jù)的第一個字段,也就是count(*)等類型的查詢可以用戏仓,返回直接是結(jié)果
let query = "select * from t_TestDB"
let items1 = try DB.run(query)
let items2 = try DB.prepare(query)
for item in items2 {
printLog(item) //一條數(shù)據(jù)
printLog(item[0]) //name
}
問題是查詢出來的數(shù)據(jù)不是字典類型疚宇,是一個數(shù)組類型,需要自己通過下標(biāo)去取值