【问题标题】:How do I call a new database connection from within a read-only database connection in GRDB?如何从 GRDB 中的只读数据库连接中调用新的数据库连接?
【发布时间】:2019-07-08 23:52:08
【问题描述】:

下面的函数返回一个Ledgers 记录。大多数时候,它会在可选的_currentReceipt 变量中找到它,或者通过搜索数据库,不需要在那里写。我想使用只读的 GRDB 数据库连接。只读数据库连接可以在不同线程上并行运行。

在极少数情况下,前两个步骤失败,我可以创建一个默认分类帐。调用try FoodyDataStack.thisDataStack.dbPool.write { writeDB in ... 会抛出致命错误,数据库连接不可重入。我正在寻找一种方法来保存该默认分类帐,而不必将整个函数包装在读写连接中。

我可以在 GRDB .read 块内的单独队列上调用 NSOperation 吗?

class func getCurrentReceipt(db: Database) throws -> Ledgers {
        if let cr = FoodyDataStack.thisDataStack._currentReceipt {
            return cr
        }
        // Fall through
        do {
            if let cr = try Ledgers.filter(Ledgers.Columns.receiptClosed == ReceiptStatus.receiptOpen.rawValue).order(Ledgers.Columns.dateModified.desc).fetchOne(db) {
                FoodyDataStack.thisDataStack._currentReceipt = cr
                return cr
            } else {
                throw FoodyDataStack.myGRDBerrors.couldNotFindCurrentReceipt
            }
        } catch FoodyDataStack.myGRDBerrors.couldNotFindCurrentReceipt {
            // Create new receipt with default store
            let newReceipt = Ledgers()
            newReceipt.dateCreated = Date()
            newReceipt.dateModified = Date()
            newReceipt.receiptStatus = .receiptOpen
            newReceipt.receiptUrgency = .immediate
            newReceipt.dateLedger = Date()
            newReceipt.uuidStore = Stores.defaultStore(db).uuidKey
            FoodyDataStack.thisDataStack._currentReceipt = newReceipt
            return newReceipt
        } catch  {
            NSLog("WARNING: Unhandled error in Ledgers.getCurrentReceipt() \(error.localizedDescription)")
        }
    }

编辑:我把这个问题留在这里,但我想我可能会进行过早的优化。我将尝试使用 dbQueue 而不是 dbPool,看看性能如何。如果速度需要,我会回到 dbPool。

【问题讨论】:

    标签: swift grdb


    【解决方案1】:

    GRDB数据库访问方法不可重入(DatabaseQueue和DatabasePool的读写方法)。

    为了帮助您解决问题,请尝试将您的数据库访问方法分为两个级别。

    第一级不暴露给应用程序的其余部分。它的方法都采用db: Database 参数。

    class MyStack {
        private var dbQueue: DatabaseQueue
    
        private func fetchFoo(_ db: Database, id: Int64) throws -> Foo? {
            return try Foo.fetchOne(db, key: id)
        }
    
        private func setBar(_ db: Database, foo: Foo) throws {
            try foo.updateChanges(db) {
                $0.bar = true
            }
        }
    }
    

    第二层的方法暴露给应用程序的其余部分。他们将一级方法包装在 readwrite 数据库访问方法中:

    class MyStack {
        func fetchFoo(id: Int64) throws -> Foo? {
            return try dbQueue.read { db in
                try fetchFoo(db, id: id)
            }
        }
    
        func setBar(id: Int64) throws {
            try dbQueue.write { db in
                guard let foo = try fetchFoo(db) else {
                    throw fooNotFound
                }
                try setBar(foo: foo)
            }
        }
    }
    

    第一层的方法可以根据需要尽可能低级,并且可以组合

    第二级的方法是高级的,不可组合:由于“数据库连接不可重入”致命错误,它们不能相互调用。它们提供了保证数据库一致性的线程安全数据库方法。

    请参阅Concurrency Guide 了解更多信息。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-12-09
      • 1970-01-01
      • 1970-01-01
      • 2014-04-09
      • 1970-01-01
      • 1970-01-01
      • 2014-09-16
      相关资源
      最近更新 更多