我正在编写一个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_BUSY结果。所有详细信息页面都检索诊断代码并更新屏幕上的一些文本。患者和医生的添加功能如下:
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)")
}
}
}
我认为这不会是一个问题,因为用户不可能同时运行两个查询,而且我确保只有一个连接。有没有人对这里可能发生的事情有任何建议?
答案 0 :(得分:2)
我相信您忘记使用sqlite3_finalize()
完成预准备语句,除非您有不匹配的打开/关闭调用或从多个线程访问数据库连接。根据sqlite指南:
如果数据库连接与未完成的准备相关联 语句或未完成的sqlite3_backup对象然后sqlite3_close() 将保持数据库连接打开并返回SQLITE_BUSY。
答案 1 :(得分:1)
除了Mostruash的答案之外,在Swift项目中,您甚至可能需要使用sqlite3_close_v2(
)方法。 sqllite3_close()
方法并不总是返回SQLITE_OK。
如果数据库连接与未完成的准备相关联 语句或未完成的sqlite3_backup对象然后sqlite3_close() 将保持数据库连接打开并返回SQLITE_BUSY。如果 使用未完成的预准备语句调用sqlite3_close_v2() 和/或未完成的sqlite3_backups,然后是数据库连接 成为一个无法使用的“僵尸”,它将自动被解除分配 当最后准备好的陈述最终确定或最后一个 sqlite3_backup完成了。 sqlite3_close_v2()接口是 旨在与垃圾收集的主机语言一起使用,以及 调用析构函数的顺序是任意的。
应用程序应该完成所有准备好的语句,关闭所有BLOB 处理并完成与之关联的所有sqlite3_backup对象 尝试关闭对象之前的sqlite3对象。如果 在仍然具有的数据库连接上调用sqlite3_close_v2() 杰出的预准备语句,BLOB句柄和/或sqlite3_backup 然后它返回SQLITE_OK并释放资源 延迟到所有准备好的陈述,BLOB处理,和 sqlite3_backup对象也被破坏。