在golang中连接数据库

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

Connection DB in golang

问题

在MVC结构的Golang中(如beego、revel),你可以将初始化文件(如语言、数据库连接等)放在哪里?

我尝试在控制器中使用,但效果不好。

一个好的解决方案是创建一个基础控制器,在这里放置所有的初始化连接、语言等内容,还是有其他更好的方法?

英文:

Where i can put initialize files like languages, connection db etc. in mvc structur golang (beego,revel)?

I tried to use in controller but it isn't good.

Is a good solution would be create base controller and put here all init connection, languages etc? or is there some other way (better)?

答案1

得分: 3

你可以使用全局变量,但我不建议这样做。在更复杂的应用程序中,数据库逻辑可能分散在多个包中,这时最好使用依赖注入。

文件:main.go

package main

import (
    "bookstore/models"
    "database/sql"
    "fmt"
    "log"
    "net/http"
)

type Env struct {
    db *sql.DB
}

func main() {
    db, err := models.NewDB("postgres://user:pass@localhost/bookstore")
    if err != nil {
        log.Panic(err)
    }
    env := &Env{db: db}

    http.HandleFunc("/books", env.booksIndex)
    http.ListenAndServe(":3000", nil)
}

func (env *Env) booksIndex(w http.ResponseWriter, r *http.Request) {
    if r.Method != "GET" {
        http.Error(w, http.StatusText(405), 405)
        return
    }
    bks, err := models.AllBooks(env.db)
    if err != nil {
        http.Error(w, http.StatusText(500), 500)
        return
    }
    for _, bk := range bks {
        fmt.Fprintf(w, "%s, %s, %s, £%.2f\n", bk.Isbn, bk.Title, bk.Author, bk.Price)
    }
}

文件:models/db.go

package models

import (
    "database/sql"
    _ "github.com/lib/pq"
)

func NewDB(dataSourceName string) (*sql.DB, error) {
    db, err := sql.Open("postgres", dataSourceName)
    if err != nil {
        return nil, err
    }
    if err = db.Ping(); err != nil {
        return nil, err
    }
    return db, nil
}
英文:

You can use global variables, but I don't suggest to do it. What happens in more complicated applications where database logic is spread over multiple packages? It's better to use dependency injection:

File: main.go

package main

import (
    "bookstore/models"
    "database/sql"
    "fmt"
    "log"
    "net/http"
)

type Env struct {
    db *sql.DB
}

func main() {
    db, err := models.NewDB("postgres://user:pass@localhost/bookstore")
    if err != nil {
        log.Panic(err)
    }
    env := &Env{db: db}

    http.HandleFunc("/books", env.booksIndex)
    http.ListenAndServe(":3000", nil)
}

func (env *Env) booksIndex(w http.ResponseWriter, r *http.Request) {
    if r.Method != "GET" {
        http.Error(w, http.StatusText(405), 405)
        return
    }
    bks, err := models.AllBooks(env.db)
    if err != nil {
        http.Error(w, http.StatusText(500), 500)
        return
    }
    for _, bk := range bks {
        fmt.Fprintf(w, "%s, %s, %s, £%.2f\n", bk.Isbn, bk.Title, bk.Author, bk.Price)
    }
}

File: models/db.go

package models

import (
    "database/sql"
    _ "github.com/lib/pq"
)

func NewDB(dataSourceName string) (*sql.DB, error) {
    db, err := sql.Open("postgres", dataSourceName)
    if err != nil {
        return nil, err
    }
    if err = db.Ping(); err != nil {
        return nil, err
    }
    return db, nil
}

答案2

得分: 1

我总是在一个包中保存我的环境变量。

例如 main.go

package main

import (
	"net/http"
	 env "github.com/vardius/example/enviroment"
)

func main() {
    //一些额外的代码,比如HTTP服务器或其他
    defer env.DB.Close()
}

然后在 enviroment 目录下的 env.go

package env

import (
	"database/sql"

	_ "github.com/go-sql-driver/mysql"
)

var (
	DB     *sql.DB
)

func connectToDB(dbURL string) *sql.DB {
	conn, err := sql.Open("mysql", dbURL)
	//检查错误

	return conn
}

func init() {
	DB = connectToDB("root:password@tcp(127.0.0.1:3306)/test")
}

这样你就可以在应用的所有部分中通过注入 env 来初始化你的数据库,并且可以在所有部分中使用它。

当然,这种解决方案也有一些缺点。首先,代码更难思考,因为组件的依赖关系不清楚。其次,测试这些组件变得更加困难,而且几乎不可能并行运行测试。使用全局连接,无法并行运行访问后端服务中相同数据的测试。

关于使用 Go 进行依赖注入,有一篇很好的文章Dependency Injection with Go

希望你会觉得这篇文章有帮助。

英文:

I always do some packega where i keep my enviroment variables.

For example main.go

package main

import (
	"net/http"
	 env "github.com/vardius/example/enviroment"
)

func main() {
    //some extra code here, http srever or something
    defer env.DB.Close()
}

end inside enviroment dir env.go

package env

import (
	"database/sql"

	_ "github.com/go-sql-driver/mysql"
)

var (
	DB     *sql.DB
)

func connectToDB(dbURL string) *sql.DB {
	conn, err := sql.Open("mysql", dbURL)
	//check for err

	return conn
}

func init() {
	DB = connectToDB("root:password@tcp(127.0.0.1:3306)/test")
}

this way you initialize once your DB and can use it in all parts of your app by injecting env

> Ofcourse this solution has some downsides. First, code is harder to
> ponder because the dependencies of a component are unclear. Second,
> testing these components is made more difficult, and running tests in
> parallel is near impossible. With global connections, tests that hit
> the same data in a backend service could not be run in parallel.

There is a great article about a Dependency Injection with Go

I hope you will find this helpfull

huangapple
  • 本文由 发表于 2016年9月10日 22:59:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/39427299.html
匿名

发表评论

匿名网友

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

确定