如何从 GRDB 中的只读数据库连接中调用新的数据库连接?
How do I call a new database connection from within a read-only database connection in GRDB?
下面的函数returns一条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。
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) {
[=10=].bar = true
}
}
}
第二层的方法暴露给应用程序的其余部分。他们将 first-level 方法包装在 read
和 write
数据库访问方法中:
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)
}
}
}
一级方法可以根据需要low-level,可以组合.
第二层的方法是高级的,不可组合:由于 "Database connections are not reentrant" 致命错误,它们不能相互调用。他们提供保证数据库一致性的thread-safe数据库方法。
有关详细信息,请参阅 Concurrency Guide。
下面的函数returns一条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。
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) {
[=10=].bar = true
}
}
}
第二层的方法暴露给应用程序的其余部分。他们将 first-level 方法包装在 read
和 write
数据库访问方法中:
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)
}
}
}
一级方法可以根据需要low-level,可以组合.
第二层的方法是高级的,不可组合:由于 "Database connections are not reentrant" 致命错误,它们不能相互调用。他们提供保证数据库一致性的thread-safe数据库方法。
有关详细信息,请参阅 Concurrency Guide。