使用SQLite.swift时,我很难查看SQLite数据库中反映的一些INSERT。
我使用断点调试我的iOS应用程序,并在插入后将应用程序容器(从设备)导出到主机硬盘。然后,我检查SQLite数据库以查看更改。 INSERT不会因此反映出来。
如果我在表上添加了诸如SELECT之类的额外代码或重新启动了应用程序,那么记录就在那儿,因此看起来似乎不是立即将设备上的磁盘整合到其他地方。我使用的是单个Connection
对象,没有并发访问,因此我不希望出现线程问题。我还尝试在事务内使用INSERT,但仍未反映在容器上。
什么时候将更改合并到磁盘上,使其真正持久化?有办法强制冲洗吗?如果应用程序被意外杀死,会发生什么情况,因为数据实际上不在数据库中而导致数据丢失?
答案 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语句之类的循环插入数据时,这种情况特别常见。
祝你有美好的一天!