【问题标题】:golang sqlite database connection poolinggolang sqlite 数据库连接池
【发布时间】: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


【解决方案1】:

documentation 说:

在没有外部同步的情况下,不能从多个 goroutine 同时使用单个连接实例及其所有派生对象(准备语句、备份操作等)。

(这是一个不同的 SQLite 驱动程序,但此限制也适用于您的驱动程序。)

当您使用 goroutines 时,您必须使用单独的数据库连接。

默认情况下,SQLite 在遇到被另一个事务锁定的数据库时会立即中止。 为了允许更多的并发,您可以通过设置繁忙超时告诉它等待其他事务完成。

使用BusyTimeout函数,如果你的SQLite驱动有,或者直接执行PRAGMA busy_timeout SQL命令。

【讨论】:

    【解决方案2】:

    请发布更多您的代码,以便我们更全面地了解发生了什么。

    但是,这里有一些想法。 Golang 默认池化数据库连接(虽然,CENTOS 似乎可能不是..)。此外,您的程序正在“停止”,因为它正在等待来自 db 连接池的打开连接。如果您希望程序的其余部分在此期间继续运行,您应该将其作为异步函数运行 - 查看goroutines here。这将有效地使您的程序按照您的意愿排队,因为连接将按照它们在可用时被请求的顺序进行分配。 Read more over here 如果您对内部结构感兴趣。

    如果您需要一些代码 sn-ps 来了解您的 goroutine 的外观,请告诉我们。

    【讨论】:

    • 我已经用我现在使用的代码更新了我的原始帖子,一切似乎都运行良好,但我不确定我是否正确使用 goroutines 和包范围的数据库连接与否。
    猜你喜欢
    • 2015-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-31
    • 2010-10-23
    • 2018-05-12
    • 2014-04-09
    相关资源
    最近更新 更多