iOS应用程序中的SQLITE\u忙错误

iOS应用程序中的SQLITE\u忙错误,ios,database,swift,sqlite,Ios,Database,Swift,Sqlite,我正在编写一个iOS应用程序,允许医生从数据库中选择诊断代码,并为sqlite3数据库中的患者付费。主页是一个表单,要求输入患者姓名和出生日期。主页上还有一个按钮,用于开始搜索诊断代码(向下钻取车身位置) 我正在使用一个带有账单选项卡、患者选项卡和医生选项卡的选项卡栏。用户可以从各自的页面添加患者和医生。除非我已导航到“账单”选项卡上的“诊断详细信息”页面,否则此选项将起作用并显示患者/医生列表中的患者/医生 我将数据库连接保存在“DatabaseManager”类中,该类用于打开和关闭设备上的

我正在编写一个iOS应用程序,允许医生从数据库中选择诊断代码,并为sqlite3数据库中的患者付费。主页是一个表单,要求输入患者姓名和出生日期。主页上还有一个按钮,用于开始搜索诊断代码(向下钻取车身位置)

我正在使用一个带有账单选项卡、患者选项卡和医生选项卡的选项卡栏。用户可以从各自的页面添加患者和医生。除非我已导航到“账单”选项卡上的“诊断详细信息”页面,否则此选项将起作用并显示患者/医生列表中的患者/医生

我将数据库连接保存在“DatabaseManager”类中,该类用于打开和关闭设备上的数据库文件

class DatabaseManager {

var db:COpaquePointer!

init(){

}
/**
*   Checks that the database file is on the device. If not, copies the database file to the device.
*   Connects to the database after file is verified to be in the right spot.
**/
func checkDatabaseFileAndOpen(){
    let theFileManager = NSFileManager.defaultManager()
    let filePath = dataFilePath()
    if theFileManager.fileExistsAtPath(filePath) {
        db = openDBPath(filePath)
    } else {

        let pathToBundledDB = NSBundle.mainBundle().pathForResource("testDML", ofType: "sqlite3")// Copy the file from the Bundle and write it to the Device
        let pathToDevice = dataFilePath()
        var error:NSError?

        if (theFileManager.copyItemAtPath(pathToBundledDB!, toPath:pathToDevice, error: nil)) {
            db = openDBPath(pathToDevice)
        } else {
            println("database failure")
        }
    }
}

/**
*   Gets the path of the database file on the device
**/
func dataFilePath() -> String {
    let paths = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)
    let documentsDirectory = paths[0] as! NSString
    return documentsDirectory.stringByAppendingPathComponent("testDML.sqlite3") as String
}

/**
*   Makes a connection to the database file located at the provided filePath
**/
func openDBPath(filePath:String) -> COpaquePointer {

    var db:COpaquePointer  = nil
    var result = sqlite3_open(filePath, &db)
    println("openResult: \(result)")
    if result != SQLITE_OK {
        sqlite3_close(db)
        println("Failed To Open Database")
        return nil
    }else {
        return db
    }
}

func closeDB() {
    var closeResult = sqlite3_close_v2(db)
    print("closed result:\(closeResult)")
    if closeResult == SQLITE_OK {
    }
}
每次执行查询时,我都会打开数据库,执行查询,然后关闭数据库。对于我运行的每个查询,我在关闭和打开数据库时都会得到SQLITE_OK,但只有在我导航到“账单”选项卡上的“诊断详细信息”页面时,添加患者和医生时才会得到SQLITE_忙碌结果。详细信息页面只需检索诊断代码并更新屏幕上的一些文本。为患者和医生添加的功能如下:

func addPatientToDatabase(inputPatient:String, dateOfBirth:String, email:String){

    var (firstName, lastName) = split(inputPatient)

    println(dateOfBirth)
    let query = "INSERT INTO Patient (pID,date_of_birth,f_name,l_name, email) VALUES (NULL, '\(dateOfBirth)', '\(firstName)', '\(lastName!)', '\(email)')"
    var statement:COpaquePointer = nil
    if sqlite3_prepare_v2(db, query, -1, &statement, nil) == SQLITE_OK {
        var sqliteResult = sqlite3_step(statement)
        if sqliteResult == SQLITE_DONE {
            println("Saved \(firstName) \(lastName!)")
        }else {
            println("Add patient failed \(sqliteResult)")
        }
    }
}

func addDoctorToDatabase(inputDoctor:String, email:String) {
    var (firstName, lastName) = split(inputDoctor)

    let query = "INSERT INTO Doctor (dID,f_name,l_name, email) VALUES (NULL,'\(firstName)', '\(lastName!)', '\(email)')"
    var statement:COpaquePointer = nil

    if sqlite3_prepare_v2(db, query, -1, &statement, nil) == SQLITE_OK {
        var sqliteResult = sqlite3_step(statement)
        if sqliteResult == SQLITE_DONE {
            println("Saved \(firstName) \(lastName!)")
        }else {
            println("Add doctor failed for \(firstName) \(lastName!) with error \(sqliteResult)")
        }

    }
}

我认为这不会是一个问题,因为用户不可能同时运行两个查询,并且我已经确保只有一个连接。有人对这里可能发生的事情有什么建议吗

我相信您忘记了使用
sqlite3\u finalize()
完成准备好的语句,除非您有不匹配的打开/关闭调用,或者您从多个线程访问数据库连接。根据sqlite指南:

如果数据库连接与未完成的连接关联,请准备 语句或未完成的sqlite3\u备份对象,然后sqlite3\u关闭() 将保持数据库连接打开,并返回SQLITE_BUSY


在Swift项目中,除了Mostruash的答案之外,您甚至可能需要使用
sqlite3\u close\u v2(
)方法
sqllite3\u close()
方法并不总是返回SQLITE\u OK

如果数据库连接与未完成的连接关联,请准备 语句或未完成的sqlite3\u备份对象,然后sqlite3\u关闭() 将保持数据库连接打开,并返回SQLITE_BUSY。如果 sqlite3_close_v2()是用未完成的预处理语句调用的 和/或未完成的sqlite3_备份,然后是数据库连接 成为一个无法使用的“僵尸”,将自动解除分配 最后一份准备好的报表定稿或最后一份 sqlite3_备份已完成。sqlite3\u close\u v2()接口是 用于垃圾收集的主机语言,以及 其中,析构函数的调用顺序是任意的

应用程序应完成所有准备好的语句,关闭所有BLOB 处理并完成与 在尝试关闭对象之前,先关闭sqlite3对象。如果 在仍具有可用性的数据库连接上调用sqlite3_close_v2() 未完成的准备语句、BLOB句柄和/或sqlite3_备份 对象,然后返回SQLITE_OK,并取消分配资源 推迟到所有准备好的语句、BLOB句柄和 sqlite3_备份对象也会被销毁


您是否正在运行查询以获取诊断信息?这是如何存储的?我将我的sqlite_步骤结果存储在一个变量中并打印它。mostruash的答案解决了我的问题。是的,我一看到答案就知道这可能是问题所在。谢谢!这解决了我的问题!我不敢相信我忽略了这一点。