数据库连接最佳实践

huangapple go评论147阅读模式
英文:

Database connection best practice

问题

我有一个使用net/http的应用程序。我在http中注册了一些处理程序,这些处理程序在我们可以继续编写响应并完成请求之前需要从数据库中获取一些数据。

我的问题是关于连接到这个数据库的最佳实践是什么。我希望每分钟处理一个请求或每秒处理10个请求。

我可以在每次请求到达时在每个处理程序中连接到数据库。(这样每个请求都会生成一个到mysql的连接?)

package main

import (
    "database/sql"
    _ "github.com/go-sql-driver/mysql"
    "net/http"
    "fmt"
)

func main() {

    http.HandleFunc("/",func(w http.ResponseWriter, r *http.Request) {
        db, err := sql.Open("mysql","dsn....")
        if err != nil {
            panic(err)
        }
        defer db.Close()

        row := db.QueryRow("select...")
        // 扫描行

        fmt.Fprintf(w,"text from database")
    })

    http.ListenAndServe(":8080",nil)
}

我可以在应用程序启动时连接到数据库。每当我需要使用数据库时,我会Ping它,如果它关闭了,我会重新连接它。如果它没有关闭,我会继续使用它。

package main

import (
    "database/sql"
    _ "github.com/go-sql-driver/mysql"
    "net/http"
    "fmt"
    "sync"
)

var db *sql.DB
var mutex sync.RWMutex

func GetDb() *sql.DB {

    mutex.Lock()
    defer mutex.Unlock()

    err := db.Ping()
    if err != nil {
        db, err = sql.Open("mysql","dsn...")
        if err != nil {
            panic(err)
        }
    }

    return db
}

func main() {

    var err error
    db, err = sql.Open("mysql","dsn....")
    if err != nil {
        panic(err)
    }

    http.HandleFunc("/",func(w http.ResponseWriter, r *http.Request) {

        row := GetDb().QueryRow("select...")
        // 扫描行

        fmt.Fprintf(w,"text from database")
    })

    http.ListenAndServe(":8080",nil)
}

这两种方式哪种是最好的,或者是否有其他更好的方式。多个请求使用同一个数据库连接是一个坏主意吗?

我不太可能创建一个超过mysql连接限制的应用程序,但我不想忽视这个事实。

英文:

I've an app that uses net/http. I register some handlers with http that need to fetch some stuff from a database before we can proceed to writing the response and be done with the request.

My question is in about which the best pratice is to connect to this database. I want this to work at one request per minute or 10 request per second.

I could connect to database within each handler every time a request comes in. (This would spawn a connection to mysql for each request?)

package main

import (
    "database/sql"
    _ "github.com/go-sql-driver/mysql"
    "net/http"
    "fmt"
)

func main() {

    http.HandleFunc("/",func(w http.ResponseWriter, r *http.Request) {
        db, err := sql.Open("mysql","dsn....")
        if err != nil {
            panic(err)
        }
        defer db.Close()

        row := db.QueryRow("select...")
        // scan row

        fmt.Fprintf(w,"text from database")
    })

    http.ListenAndServe(":8080",nil)
}

I could connect to database at app start. Whenever I need to use the database I Ping it and if it's closed I reconnect to it. If it's not closed I continue and use it.

package main

import (
    "database/sql"
    _ "github.com/go-sql-driver/mysql"
    "net/http"
    "fmt"
    "sync"
)

var db *sql.DB
var mutex sync.RWMutex

func GetDb() *sql.DB {

    mutex.Lock()
    defer mutex.Unlock()

    err := db.Ping()
    if err != nil {
        db, err = sql.Open("mysql","dsn...")
        if err != nil {
            panic(err)
        }
    }

    return db
}

func main() {

    var err error
    db, err = sql.Open("mysql","dsn....")
    if err != nil {
        panic(err)
    }

    http.HandleFunc("/",func(w http.ResponseWriter, r *http.Request) {

        row := GetDb().QueryRow("select...")
        // scan row

        fmt.Fprintf(w,"text from database")
    })

    http.ListenAndServe(":8080",nil)
}

Which of these ways are the best or is there another way which is better. Is it a bad idea to have multiple request use the same database connection?

It's unlikly I will create an app that runs into mysql connection limit, but I don't want to ignore the fact that there's a limit.

答案1

得分: 12

最好的方法是在应用程序启动时创建数据库,并在此后使用该句柄。此外,sql.DB 类型可以安全地进行并发使用,因此您甚至不需要互斥锁来锁定其使用。最后,根据您的驱动程序,数据库句柄将自动重新连接,因此您不需要自己进行重新连接。

英文:

The best way is to create the database once at app start-up, and use this handle afterwards. Additionnaly, the sql.DB type is safe for concurrent use, so you don't even need mutexes to lock their use. And to finish, depending on your driver, the database handle will automatically reconnect, so you don't need to do that yourself.

答案2

得分: -4

var db *sql.DB
var Database *Database

func init(){
hostName := os.Getenv("DB_HOST")
port := os.Getenv("DB_PORT")
username := os.Getenv("DB_USER")
password := os.Getenv("DB_PASS")
database := os.Getenv("DB_NAME")
var err error
db, err = sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", username, password, hostName, port, database))
defer db.Close()
if err != nil {
panic(err)
}

err = db.Ping()
if err != nil {
panic(err)
}

Database := &Database{conn: db}

}

type Database struct {
conn *sql.DB
}

func (d *Database) GetConn() *sql.DB {
return d.conn
}

func main() {
row := Database.GetConn().QueryRow("select * from")
}

英文:
var db *sql.DB
var Database *Database

func init(){
  hostName := os.Getenv("DB_HOST")
  port := os.Getenv("DB_PORT")
  username := os.Getenv("DB_USER")
  password := os.Getenv("DB_PASS")
  database := os.Getenv("DB_NAME")
  var err error
  db, err = sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", username, password, hostName, port, database))
  defer db.Close()
  if err != nil {
     panic(err)
  }
  
  err = db.Ping()
  if err != nil {
    panic(err)
  }
  
  Database := &Database{conn: db}
   
} 

type Database struct {
  conn *sql.DB
}

func (d *Database) GetConn() *sql.DB {
   return d.conn
}

func main() {
    row := Database.GetConn().QueryRow("select * from")
}

答案3

得分: -9

我建议在init()函数中建立与数据库的连接。为什么呢?因为init()函数在main()函数之前被保证执行,你肯定希望在真正开始工作之前确保你的数据库配置正确设置。

var db *sql.DB

func GetDb() (*sql.DB, error) {
   db, err = sql.Open("mysql","dsn...")
   if err != nil {
      return nil, err
   }
   return db, nil
}

func init() {
   db, err := GetDb()
   if err != nil {
      panic(err)
   }
   err = db.Ping()
   if err != nil {
      panic(err)
   }
}

我没有测试上面的代码,但它应该是这个样子的。

英文:

I'd recommend make the connection to your database on init().
Why? cause init() is guaranteed to run before main() and you definitely want to make sure you have your db conf set up right before the real work begins.

var db *sql.DB

func GetDb() (*sql.DB, error) {
   db, err = sql.Open("mysql","dsn...")
   if err != nil {
      return nil, err
   }
   return db, nil
}

func init() {
   db, err := GetDb()
   if err != nil {
      panic(err)
   }
   err = db.Ping()
   if err != nil {
      panic(err)
   }
}

I did not test the code above but it should technically look like this.

huangapple
  • 本文由 发表于 2014年7月25日 16:40:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/24951543.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定