Swift笔记42:WCDB

WCDB(WeChat Database)是由 WeChat 开发的开源跨平台数据库框架。它基于 SQLite 和 SQLCipher,提供高效全面的功能。WCDB 支持多种编程语言,包括 Swift、Objective-C、C++、Java 和 Kotlin。

查看demo

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。待更新。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容