使用多线程读取 FMDB 数据库

Posted

技术标签:

【中文标题】使用多线程读取 FMDB 数据库【英文标题】:FMDB database read using multithreading 【发布时间】:2016-11-18 07:07:12 【问题描述】:

我在 ios 中为 sqlite 使用 FMDB 数据库库。如何在 FMDB 中同时执行多个读取操作。目前我正在使用 FMDB 数据库队列。

【问题讨论】:

【参考方案1】:

FMDatabaseQueue 序列化所有数据库访问。 FMDatabaseQueue 不能同时执行多个读取操作,而且永远不会:这不是 FMDatabaseQueue 的目的。

不幸的是,FMDB 不提供任何其他安全的并发模型。您可以使用原始 FMDatabase 连接,并自己处理写入序列化和并行读取。例如,您可以将数据库调用包装在并发 DispatchQueue 中:

let dbQueue = DispatchQueue(label: "database", attributes: .concurrent)
func read(block: () -> ()) 
    // Since the queue is concurrent, several readers can execute at
    // the same time.
    dbQueue.sync(execute: block)

func write(block: () -> ()) 
    // The barrier flag makes sure that only one writer block is executing
    // at a given time, and that no reader is currently executing.
    dbQueue.sync(flags: .barrier, execute: block)


let db = FMDatabase(...)
read 
    // Select from db

write 
    // Write in db

不过,此解决方案有一些注意事项:并发读取的数量不受限制,您不会从围绕事务或保存点的 DatabaseQueue 高级 API 中受益,并且read 方法不会阻止您执行数据库更新。

您可以查看 FMDB 的替代方案:GRDB.swift 库。它与 FMDB 非常相似。不过,与 FMDB 不同的是,它提供了一个 DatabasePool 类,可以避免上面列出的所有警告:https://github.com/groue/GRDB.swift#database-pools

let dbPool = DatabasePool(path: ...)

// Serialized writes
try dbPool.write  db in
    try db.execute("CREATE TABLE ...")
    try db.execute("INSERT INTO ...")


// Concurrent reads
dbPool.read  db in
    for row in Row.fetch(db, "SELECT * FROM ...") 
        ...
    
    let count = Int.fetchOne(db, "SELECT COUNT(*) FROM ...")!

【讨论】:

FMDB也有DatabasePool,有什么用? FMDB 的 DatabasePool 与 GRDB 的 DatabasePool 完全不同,尽管它们的名称相同。 FMDB DatabasePool 是dangerous,而 GRDB DatabasePool 是坚如磐石的。【参考方案2】:

FMDB 队列适用于多线程。目前我在多线程应用程序中使用它,没有发现任何问题。

请描述您在使用 FMDB 队列时遇到的问题

示例

      var queue = FMDatabaseQueue(path:"db path")

      queue.inTransaction (db, rollback) in
        do
        
            let resultset = try db.executeQuery(queryString, values: [])
            while(resultset.next())
                //do your task

             

        
        catch
        
            rollback.memory = true
            print(error)
        

    

【讨论】:

【参考方案3】:

检查此链接对您有用:

http://www.theappguruz.com/blog/use-sqlite-database-swift

获取数据:

@IBAction func findContact(_ sender: AnyObject) let contactDB = FMDatabase(path: databasePath as String)

if (contactDB?.open())! 
    let querySQL = "SELECT address, phone FROM CONTACTS WHERE name = '\(name.text!)'"

    let results:FMResultSet? = contactDB?.executeQuery(querySQL,
                                           withArgumentsIn: nil)

    if results?.next() == true 
        address.text = results?.string(forColumn: "address")
        phone.text = results?.string(forColumn: "phone")
        status.text = "Record Found"
     else 
        status.text = "Record not found"
        address.text = ""
        phone.text = ""
    
    contactDB?.close()
 else 
    print("Error: \(contactDB?.lastErrorMessage())")

【讨论】:

以上是关于使用多线程读取 FMDB 数据库的主要内容,如果未能解决你的问题,请参考以下文章

iOS FMDB 多线程操作失败

FMDB 的多线程问题

IOS:FMDB使用databaseQueue实现数据库操作线程安全

FMDB的线程安全

FMDB

如何在 IOS Swift 中使用 SQLite 使用 FMDB 处理多个线程