【问题标题】:Does db.Close() need to be called?是否需要调用 db.Close()?
【发布时间】:2021-02-14 12:10:27
【问题描述】:

到目前为止,Go 最难的部分是理解如何组织代码。表面上看起来非常简单,但每次我尝试做任何事情时,我都会遇到循环导入或“exported func Start 返回未导出的类型 models.dbStore,使用起来很烦人”之类的东西。

使用以下代码如何调用db.Close() 或者我真的不明白我应该如何为我的模型提供数据库。这是我得到的:

App.go

package app

import (
    "database/sql"

    // Comment
    _ "github.com/mattn/go-sqlite3"
)

var (
    // DB The database connection
    db *sql.DB
)

// Setup Sets up the many many app settings
func Setup() {
    d, err := sql.Open("sqlite3", "./foo.db")
    if err != nil {
        panic(err)
    }

    // TODO: How does the DB get closed?
    // defer db.Close()
    db = d
}

// GetDB Returns a reference to the database
func GetDB() *sql.DB {
    return db
}

Users.go

package models

import (
    "github.com/proj/org/app"
)

// User struct
type User struct {
    ID int
}

// CreateUser Creates a user
func (u *User) CreateUser() (int64, error) {

    // For the sake of brevity just make sure you can
    // "connect" to the database
    if err := app.GetDB().Ping(); err != nil {
        panic(err)
    }

    return 1234, nil
}

main.go

package main

import (
    "fmt"
    "net/http"

    _ "github.com/mattn/go-sqlite3"
    "github.com/proj/org/app"
    "github.com/proj/org/models"
)

func homeHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "You are home")
}

func subscribeHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Subscribing...")
    u := models.User{}

    u.CreateUser()

}

func main() {
    fmt.Println("Running")

    app.Setup()

    http.HandleFunc("/", homeHandler)
    http.HandleFunc("/subscribe", subscribeHandler)

    err := http.ListenAndServe(":9090", nil)
    if err != nil {
        panic(err)
    }
}

我想过做一个app.Shutdown(),但这不适用于我最常见的用例CTRL-C。如果我不关闭数据库,似乎数据库连接只会增长......只是试图理解。

【问题讨论】:

  • 随着项目的发展和成熟,您可能希望稍微改变一下它。就目前而言,您的app main 包都与数据库耦合,从设计的角度来看,您可能希望避免这种情况。将它们解耦将有助于缓解您的一些依赖问题,但需要在设计时更加小心。
  • @Adrian 你有没有显示这种解耦的 goto 示例应用程序?我看过一些,例如 Netlify GoTrue API,但有时我很难理解大局,因为有太多的包/抽象。

标签: go


【解决方案1】:

不需要关闭数据库。

返回的数据库对于多个 goroutine 并发使用是安全的,并且 维护自己的空闲连接池。因此,打开功能 应该只调用一次。很少需要关闭数据库。

发件人:https://golang.org/pkg/database/sql/#Open

当您的程序退出时,任何打开的连接都将关闭,它不会在以太中的某处保持打开状态,等待您的程序重新启动,因此不要担心当您 CTRL-C 应用程序时连接“增长”。


但是,如果您仍然想关闭它,那么您可以像使用 GetDB 一样导出 CloseDB 函数。

App.go

// ...

func CloseDB() error {
    return db.Close()
}

main.go

// ...

func main() {
    // ...

    app.Setup()
    defer app.CloseDB()

    // ...

}

【讨论】:

  • 谢谢@mkopriva 我原以为那将是特定于驱动程序的,所以没想到那里。还有一些如何错过公开方法,以便我可以推迟到 app 包之外。
  • 不关闭 DB 可能会导致连接超时。您可以决定不关闭它。没什么大不了的,但如果您的流程启动和停止非常快,这将是一个问题。
  • 所以不是每个处理程序都调用 db.open() - 他们应该都传递一个共享的数据库实例吗?
  • @alex 他们不必传递它。但他们需要分享它,传递它是一种分享方式。
猜你喜欢
  • 2014-09-17
  • 1970-01-01
  • 2021-01-02
  • 1970-01-01
  • 1970-01-01
  • 2012-03-20
  • 2015-10-14
  • 2016-11-09
相关资源
最近更新 更多