何时使用SQLite.swift将记录提交到磁盘



当使用SQLite.swift.时,我很难看到一些INSERT反映在SQLite数据库中

我用断点调试我的iOS应用程序,插入后我将应用程序容器(从设备(导出到主机硬盘。然后我检查SQLite数据库以查看更改。INSERT不会因此而反映出来。

如果我在表上添加额外的代码(如SELECT(或重新启动应用程序,那么记录就在那里,所以设备上磁盘的整合似乎不是直接发生的,而是在其他时间点发生的。我使用的是单个Connection对象,并且没有并发访问,所以我不希望出现线程问题。我还尝试在事务中使用INSERT,但仍然没有反映在容器中。

什么时候将更改整合到磁盘上,使其真正持久?有办法强行冲洗吗?如果应用程序意外终止,会发生什么?数据是否会因为不在数据库中而丢失?

通常,在C-API级别,只有在使用事务时才会缓存结果。在该级别上,sqlite3_reset()和/或sqlite3_finalize()将结束该语句并使其被写入。不过我的猜测是你没有使用交易。

我在网上发现了几篇帖子,建议打开数据库的活动查询可以防止缓存刷新到数据库。但是,如果没有看到您的代码,就不可能知道是否发生了这种情况。

如果你想的话,你可以显式地BEGIN一个事务,COMMIT它来强制刷新

另一个需要检查的是PRAGMA SYNCHRONOUS值(docs(。它通常设置为FULL (2),但您可以尝试将其设置为EXTRA (3)

更新:

我试图使用SQLite.swift复制您所描述的内容,但写入总是即时的,并且可以立即从不同的连接读取。这是我写的代码:

import UIKit
import SQLite
class ViewController: UIViewController {
private static let REUSE_DB_CONN:Bool = true
private static let DB_NAME = "SQLiteFlushTester.sqlite3"
let pragma:String? = "PRAGMA foreign_keys = ON;"
var connection:Connection?
let fooTable = Table("FooTable")
let id = Expression<Int64>("id")
func dbDefaultPath(name: String = ViewController.DB_NAME) -> String {
let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
let fmgr = FileManager.default
if (!fmgr.fileExists(atPath: path)) {
print("Directory does not exist at (path)")
do {
try fmgr.createDirectory(atPath: path, withIntermediateDirectories: true, attributes: nil)
} catch {
print("Could not create directory (path)")
}
}
return "(path)/(name)"
}
func dbConn() -> Connection? {
if let connection = connection {
print("Recycling connection")
return connection
}
let dbPath = dbDefaultPath()
do {
let dbConn = try Connection(dbPath)
if let pragma = pragma {
try dbConn.execute(pragma)
}
if ( ViewController.REUSE_DB_CONN ) {
connection = dbConn
}
return dbConn
} catch let error {
print("Error opening DB (error)?")
return nil
}
}
func createTestTable(_ db:Connection) throws {
try db.run(fooTable.create { t in
t.column(id, primaryKey: true)
})
}
func insertIdIntoFoo(_ db:Connection) {
let randval:Int64 = Int64(arc4random_uniform(10000))
do {
let insert = fooTable.insert(id <- randval)
let rowid = try db.run(insert)
print("Inserted to row id (rowid)")
} catch let error {
print("Error inserting value: (error)")
return
}
}
@IBAction func doAnInsert(_ sender: Any) {
guard let db = dbConn() else {return}
insertIdIntoFoo(db)
}
override func viewDidLoad() {
super.viewDidLoad()
guard let db = dbConn() else { return }
do {
try createTestTable(db)
} catch let error {
print("Error creating table: (error)")
return
}
}
}

我从sqlite3命令行工具打开数据库,并在按下ViewController上触发IBAction的按钮时查看更新,行立即反映在数据库中。重用(或不重用(连接没有任何区别(请参阅REUSE_DB_CONN标志(。

我在访问数据库时遇到了同样的问题,我发现当我使用for或while语句之类的循环插入数据时,这种情况尤其频繁。

  1. 确保通过序列化对数据库的访问来控制数据流
  2. 请确保在执行插入过程的整个过程中都打开了数据库,否则会产生问题。如果在每个循环周期打开和关闭数据库,那就是一个问题

祝你今天愉快!

最新更新