WCDB(WeChat Database)是由 WeChat 开发的开源跨平台数据库框架。它基于 SQLite 和 SQLCipher,提供高效全面的功能。WCDB 支持多种编程语言,包括 Swift、Objective-C、C++、Java 和 Kotlin。
WCDB 优点
高性能:针对移动设备进行了优化,提供快速的查询执行和高效的数据存储。WCDB的查询速度比Core Data和FMDB更快。
内存使用率低:WCDB在内存使用方面比其他数据库更有效率。
易用性:提供简单直观的 API 来执行数据库操作,从而减少开发工作量。
支持 SQL 和键值存储:通过支持传统的 SQL 查询和键值存储系统来提供灵活性。
跨语言兼容性:与 Swift 和 Objective-C 无缝协作,适用于 iOS/macOS 项目。
支持SQLCipher加密:WCDB支持数据库加密,保护用户的数据安全。
数据库升级: WCDB的数据库升级很简单,我们知道不销毁表的情况下,无法对列直接进行删除。
所以WCDB做了这样的处理:直接在模型绑定里进行列的是否存储操作,新加列可以在case 里加上,当db.create(table:of:)调用时会自动在表里新增列,'删除'列可在case 里删除,当db.create(table:of:)调用时会自动在表里忽略此列,但是表里此列并没有删除,且以前此列的值不会删除
WCDB 缺点
有限的高级功能:可能缺少其他框架提供的一些高级数据库功能。
SQLite 依赖项:由于 WCDB 包装了 SQLite,因此它的功能本质上仅限于 SQLite 的功能集。
GitHub地址
教程文档
轻量级Browser
安装Pod
Installing WCDB.swift (2.1.9)
Installing WCDBOptimizedSQLCipher (1.4.6)
创建数据库
private func createDB() -> Database {
let db = Database(at: path)
print("创建数据库:", path)
return db
}
创建表
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)
}
}
添加监控
// 全局性能监控
Database.globalTracePerformance { tag, path, handleId, sql, cost in
print("WCDB数据库性能指标: tag \(tag) id \(handleId) at path \(path) takes \(cost) seconds to execute sql \(sql)")
}
// 全局错误监控
Database.globalTraceError { (error: WCDBError) in
#if DEBUG
assert(error.level != .Fatal)
#endif
if error.level == .Ignore {
print("可忽略WCDB数据库信息", error)
} else {
print("WCDB数据库错误", error)
}
}
表操作
增加
只是单纯的插入数据,主键冲突可能会失败
如果要支持多参数和数组的话,函数名重载
public func insert<T: TableEncodable>(objects:T..., intoTable tableName: String){
do {
try db?.insert(objects, intoTable: tableName)
}catch let error {
debugPrint(error.localizedDescription)
}
}
// 传入数组
public func insert<T: TableEncodable>(objects: [T], intoTable tableName: String) {
do {
try db?.insert(objects, intoTable: tableName)
} catch {
debugPrint(error.localizedDescription)
}
}
插入数据,当数据出现冲突时会失败,而后两个在主键冲突等约束冲突出现时,insertOrReplace会把新数据会覆盖旧数据
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)
}
}
执行插入或忽略对象。如果当前表中已经存在相同的主键或行id,则忽略该对象。
insertOrIgnore则是会忽略冲突数据,而不产生错误。
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 表内,满足 condition 的数据,按照 orderList 的方式进行排序,然后从头开始第 offset 行数据后的 limit 行数据按照Condition规则删除
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)
改
更改和插入一样,如有存在主键并且冲突,更新失败
根据条件更新一条数据(推荐)
let object = ExampleItem()
object.authorNumber = Int.random(in: 0...10)
object.authorName = "张三"
object.desc = "更新一条数据"
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 == "更新一条数据" && ExampleItem.Properties.authorName > 0)
查询
下例中读取本地数据库allObjects ,是读取所有数据
allObjectsA添加规则查找,condition定义条件,limit条数,offset(N)下移N。
/// 读取本地json数据
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 文件与代码模版,官网有教程。点这里
2 同时WCDB,Database 和 Table 都能直接发起事务,事务提升性能批量处理。而事务可以保证一段操作的原子性,避免多线程bug。待更新。