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

时间:2018-07-12 14:53:16

标签: ios sqlite sqlite.swift

使用SQLite.swift时,我很难查看SQLite数据库中反映的一些INSERT。

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

如果我在表上添加了诸如SELECT之类的额外代码或重新启动了应用程序,那么记录就在那儿,因此看起来似乎不是立即将设备上的磁盘整合到其他地方。我使用的是单个Connection对象,没有并发访问,因此我不希望出现线程问题。我还尝试在事务内使用INSERT,但仍未反映在容器上。

什么时候将更改合并到磁盘上,使其真正持久化?有办法强制冲洗吗?如果应用程序被意外杀死,会发生什么情况,因为数据实际上不在数据库中而导致数据丢失?

2 个答案:

答案 0 :(得分:1)

通常,在C-API级别,仅在使用事务时才缓存结果。在该级别上, #Simulate example data library(tidyverse) N <- 2000 data <- data.frame(id = 1:2000,age1 = rnorm(N,6:8),age2 = rnorm(N,7:9),age3 = rnorm(N,8:10), age4 = rnorm(N,9:11),age5 = rnorm(N,10:12),pub1 = rnorm(N,1:4),pub2 = rnorm(N,1:4), pub3 = rnorm(N,1:4),pub4 = rnorm(N,1:4),pub5 = rnorm(N,1:4)) data <- data %>% mutate_at(vars(starts_with("pub")), funs(round(replace(., .< 0, NA), 0))) 和/或   sqlite3_reset()将结束该语句并使其被写入。不过我的猜测是您没有使用交易。

我在网上发现了几个posts,这表明对数据库打开活动查询可能会阻止缓存刷新到数据库。但是,如果没有看到您的代码,实际上是不可能知道是否正在发生这种情况。

如果需要,您可以显式sqlite3_finalize()进行事务处理,BEGIN强制进行刷新。

要检查的另一件事是COMMIT值(docs)。通常将其设置为PRAGMA SYNCHRONOUS,但是您可以尝试将其设置为FULL (2)

更新:

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

EXTRA (3)

我从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标志)。

答案 1 :(得分:1)

我在访问数据库时遇到了同样的问题,并且发现当我使用for或while语句之类的循环插入数据时,这种情况特别常见。

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

祝你有美好的一天!