【发布时间】:2014-10-03 15:16:55
【问题描述】:
当我在读取数据库的同时调用数据库写入时,我遇到了 SQLite 在我的机器上扔扳手的问题。当不同的方法碰巧同时尝试访问数据库时,就会发生这种情况。
我所做的与this thread 所做的类似,接受的答案解释了如何使用数据库事务来避免数据库锁定。
这是我的一些代码:
stmt, err := dbtx.Prepare(`statement`)
if err != nil {
log.Fatal(err)
}
_, err = stmt.Exec(values, values, values)
if err != nil {
log.Fatal(err)
}
err = dbtx.Commit()
if err != nil {
fmt.Println("database lock?")
fmt.Println(err)
dbtx.Rollback()
}
fmt.Println("Database storage complete!")
令人困惑的是程序在输出后存在:
database lock?
database is locked
Database storage complete!
2014/09/09 18:33:11 database is locked
exit status 1
我不希望我的程序在数据库锁定时停止,我希望它将数据存储在内存中并继续其业务,直到数据库解锁并且我可以重试。
是否有一些标准方法可以实现这一点,可能是某种队列或数据结构,或者是否有特定于数据库的方法来解决这个问题?
为什么输出Database storage complete!后程序退出?
编辑:
我相信我已经解决了这个问题,但我不能确定。我正在使用 goroutines 和包范围的数据库连接。以前,我的代码中的每个 func 在被调用时都会初始化一个数据库连接。现在,我在包顶部定义了一个用于 DB 连接的“全局”变量,并在任何例程开始之前进行了初始化。简而言之,代码如下:
var nDB *sql.DB
稍后在主函数中...
mypkg.InitDB()
go mypkg.RunDatabaseOperations()
mypkg.BeginHTTPWatcher(rtr)
InitDB() 定义如下:
func InitDB() {
fmt.Println("Init DB ...")
var err error
nDB, err = sql.Open("sqlite3", "./first.db")
if err != nil {
log.Fatal(err)
}
if nDB == nil {
log.Fatal(err)
}
fmt.Printf("nDB: %v\n", ODB)
fmt.Println("testing db connection...")
err2 := nDB.Ping()
if err2 != nil {
log.Fatalf("Error on opening database connection: %s", err2.Error())
}
}
因此,RunDatabaseOperations 定期扫描在线资源以查找数据,并在发生更改时将其存储到数据库中(每隔几秒一次)。 BeginHTTPWatcher 侦听 HTTP 请求,因此可以从正在运行的程序中读取数据,并通过网络将数据传输给数据的请求者,无论是本地请求还是外部请求。我还没有遇到问题。
【问题讨论】:
-
2014/09/09 18:33:11 database is locked看起来像log.Fatal(err)工作。你能提供更多信息,做测试样品吗?您使用哪个 sqlite 提供商? -
我正在使用
github.com/mattn/go-sqlite3 -
似乎是并发问题...您是否同时运行此代码?如果是这样,请发布更多代码,以便我们了解发生了什么。
-
根据您接受的答案,您是否更改了 goroutine RunDatabaseOperations() 以建立单独的数据库连接,而不是使用全局包范围的连接?
-
我正在使用全局包范围的连接,但每个例程都会使用
.Begin()创建一个新事务。另外,根据 mattn 自己的建议,在InitDB函数中,我现在使用以下额外参数打开数据库:nDB, err = sql.Open("sqlite3", "./first.db?cache=shared&mode=wrc")。
标签: database sqlite error-handling go