WCDB(WeChat Database)是由 WeChat 開發(fā)的開源跨平臺數(shù)據(jù)庫框架昂利。它基于 SQLite 和 SQLCipher窝稿,提供高效全面的功能祝闻。WCDB 支持多種編程語言奕谭,包括 Swift、Objective-C贵涵、C++列肢、Java 和 Kotlin。
WCDB 優(yōu)點
高性能:針對移動設(shè)備進行了優(yōu)化宾茂,提供快速的查詢執(zhí)行和高效的數(shù)據(jù)存儲瓷马。WCDB的查詢速度比Core Data和FMDB更快。
內(nèi)存使用率低:WCDB在內(nèi)存使用方面比其他數(shù)據(jù)庫更有效率跨晴。
易用性:提供簡單直觀的 API 來執(zhí)行數(shù)據(jù)庫操作欧聘,從而減少開發(fā)工作量。
支持 SQL 和鍵值存儲:通過支持傳統(tǒng)的 SQL 查詢和鍵值存儲系統(tǒng)來提供靈活性端盆。
跨語言兼容性:與 Swift 和 Objective-C 無縫協(xié)作怀骤,適用于 iOS/macOS 項目。
支持SQLCipher加密:WCDB支持數(shù)據(jù)庫加密焕妙,保護用戶的數(shù)據(jù)安全蒋伦。
數(shù)據(jù)庫升級: WCDB的數(shù)據(jù)庫升級很簡單,我們知道不銷毀表的情況下访敌,無法對列直接進行刪除凉敲。
所以WCDB做了這樣的處理:直接在模型綁定里進行列的是否存儲操作,新加列可以在case 里加上寺旺,當(dāng)db.create(table:of:)調(diào)用時會自動在表里新增列爷抓,'刪除'列可在case 里刪除,當(dāng)db.create(table:of:)調(diào)用時會自動在表里忽略此列,但是表里此列并沒有刪除阻塑,且以前此列的值不會刪除
WCDB 缺點
有限的高級功能:可能缺少其他框架提供的一些高級數(shù)據(jù)庫功能蓝撇。
SQLite 依賴項:由于 WCDB 包裝了 SQLite,因此它的功能本質(zhì)上僅限于 SQLite 的功能集陈莽。
GitHub地址
教程文檔
輕量級Browser
安裝Pod
Installing WCDB.swift (2.1.9)
Installing WCDBOptimizedSQLCipher (1.4.6)
創(chuàng)建數(shù)據(jù)庫
private func createDB() -> Database {
let db = Database(at: path)
print("創(chuàng)建數(shù)據(jù)庫:", path)
return db
}
創(chuàng)建表
public func createTable<T: TableCodable>(name: String? = nil, model: T.Type) {
do {
try db.create(table: name ?? "\(T.self)", of: T.self)
} catch {
debugPrint(error.localizedDescription)
}
}
添加監(jiān)控
// 全局性能監(jiān)控
Database.globalTracePerformance { tag, path, handleId, sql, cost in
print("WCDB數(shù)據(jù)庫性能指標: tag \(tag) id \(handleId) at path \(path) takes \(cost) seconds to execute sql \(sql)")
}
// 全局錯誤監(jiān)控
Database.globalTraceError { (error: WCDBError) in
#if DEBUG
assert(error.level != .Fatal)
#endif
if error.level == .Ignore {
print("可忽略WCDB數(shù)據(jù)庫信息", error)
} else {
print("WCDB數(shù)據(jù)庫錯誤", error)
}
}
表操作
增加
只是單純的插入數(shù)據(jù),主鍵沖突可能會失敗
如果要支持多參數(shù)和數(shù)組的話渤昌,函數(shù)名重載
public func insert<T: TableEncodable>(objects:T..., intoTable tableName: String){
do {
try db?.insert(objects, intoTable: tableName)
}catch let error {
debugPrint(error.localizedDescription)
}
}
// 傳入數(shù)組
public func insert<T: TableEncodable>(objects: [T], intoTable tableName: String) {
do {
try db?.insert(objects, intoTable: tableName)
} catch {
debugPrint(error.localizedDescription)
}
}
插入數(shù)據(jù),當(dāng)數(shù)據(jù)出現(xiàn)沖突時會失敗走搁,而后兩個在主鍵沖突等約束沖突出現(xiàn)時独柑,insertOrReplace會把新數(shù)據(jù)會覆蓋舊數(shù)據(jù)
public func insertOrReplace<T: TableCodable>(_ objects: T..., tableName: String? = nil, on propertyConvertibleList: [PropertyConvertible]? = nil) {
let table = db.getTable(named: tableName ?? "\(T.self)", of: T.self)
do {
try table.insertOrReplace(objects, on: propertyConvertibleList)
} catch {
debugPrint(error.localizedDescription)
}
}
執(zhí)行插入或忽略對象。如果當(dāng)前表中已經(jīng)存在相同的主鍵或行id私植,則忽略該對象忌栅。
insertOrIgnore則是會忽略沖突數(shù)據(jù),而不產(chǎn)生錯誤曲稼。
public func insertOrIgnore<T: TableCodable>(_ objects: T..., tableName: String? = nil, on propertyConvertibleList: [PropertyConvertible]? = nil) {
let table = db.getTable(named: tableName ?? "\(T.self)", of: T.self)
do {
try table.insertOrIgnore(objects, on: propertyConvertibleList)
} catch {
debugPrint(error.localizedDescription)
}
}
刪
將 table 表內(nèi)索绪,滿足 condition 的數(shù)據(jù),按照 orderList 的方式進行排序贫悄,然后從頭開始第 offset 行數(shù)據(jù)后的 limit 行數(shù)據(jù)按照Condition規(guī)則刪除
let condition: Condition = ExampleItem.Properties.authorNumber <= 3
try? DBManager.shared.db.delete(fromTable: "ExampleItem",
where: condition,
orderBy: [ExampleItem.Properties.authorNumber.asOrder().order(.descending)],
limit: 100)
改
更改和插入一樣瑞驱,如有存在主鍵并且沖突,更新失敗
根據(jù)條件更新一條數(shù)據(jù)(推薦)
let object = ExampleItem()
object.authorNumber = Int.random(in: 0...10)
object.authorName = "張三"
object.desc = "更新一條數(shù)據(jù)"
try? DBManager.shared.db.update(table: "ExampleItem",
on: ExampleItem.Properties.all,
with: object,
where: ExampleItem.Properties.authorNumber == 1)
更新某個Value
let row: [ColumnCodable] = ["update with row"]
try? DBManager.shared.db.update(table: "ExampleItem",
on: ExampleItem.Properties.desc,
with: row,
where: ExampleItem.Properties.desc == "更新一條數(shù)據(jù)" && ExampleItem.Properties.authorName > 0)
查詢
下例中讀取本地數(shù)據(jù)庫allObjects 窄坦,是讀取所有數(shù)據(jù)
allObjectsA添加規(guī)則查找唤反,condition定義條件,limit條數(shù)鸭津,offset(N)下移N彤侍。
/// 讀取本地json數(shù)據(jù)
func readLocalDataBase() {
do {
let allObjects: [ExampleItem] = try DBManager.shared.db.getObjects(on: ExampleItem.Properties.all, fromTable: "\(ExampleItem.self)")
let condition: Condition = ExampleItem.Properties.authorNumber < 50 // && ExampleItem.Properties.authorName == "abc"
let allObjectsA: [ExampleItem] = try DBManager.shared.db.getObjects(on: ExampleItem.Properties.all, fromTable: "ExampleItem", where: condition, limit: 10, offset: 0)
let _ = allObjectsA.map {
print($0.authorNumber ?? 0)
print($0.authorName ?? "")
}
bookArray = allObjectsA
mTableView.reloadData()
} catch {}
}
其它
1 文件與代碼模版,官網(wǎng)有教程曙博。點這里
2 同時WCDB拥刻,Database 和 Table 都能直接發(fā)起事務(wù),事務(wù)提升性能批量處理父泳。而事務(wù)可以保證一段操作的原子性般哼,避免多線程bug。待更新惠窄。