I'm opening the sqlite database in the main function
db, err := sql.Open("sqlite3", "./libreread.db")
CheckError(err)
defer db.Close()
And I have these router handlers
r.GET("/", GetHomePage)
r.GET("/signin", GetSignIn)
r.POST("/signin", PostSignIn)
...
How to pass that db value through the router handler func PostSignin(c *gin.Context) ?
So that I could avoid opening and closing the database each time in the functions.
Thanks!
I usually create a middleware that sets a context value.
func Site(activeSite *sites.Site) gin.HandlerFunc {
return func(c *gin.Context) {
c.Set(constants.CONTEXT_SITE, activeSite)
c.Next()
}
}
```go
r.Use(middleware.Site(site))
And then inside your handler:
```go
site := c.MustGet(constants.CONTEXT_SITE).(*sites.Site)
Same concept applies to database objects :)
@mysticmode you can put db into a custom Env type:
type Env struct {
db *sql.DB
}
func (e *Env) GetHomePage(c *gin.Context) {
//e.db.Query("SELECT * FROM USER")
//omitted..
}
func (e *Env) GetSignIn(c *gin.Context) {
//omitted...
}
func (e *Env) PostSignIn(c *gin.Context) {
//omitted...
}
func main() {
db, _ := sql.Open("sqlite3", "./libreread.db")
r := gin.New()
env := &Env{db: db}
r.GET("/", env.GetHomePage)
r.GET("/signin", env.GetSignIn)
r.POST("/signin", env.PostSignIn)
}
@mysticmode you can put db into a custom Env type:
type Env struct { db *sql.DB } func (e *Env) GetHomePage(c *gin.Context) { //e.db.Query("SELECT * FROM USER") //omitted.. } func (e *Env) GetSignIn(c *gin.Context) { //omitted... } func (e *Env) PostSignIn(c *gin.Context) { //omitted... } func main() { db, _ := sql.Open("sqlite3", "./libreread.db") r := gin.New() env := &Env{db: db} r.GET("/", env.GetHomePage) r.GET("/signin", env.GetSignIn) r.POST("/signin", env.PostSignIn) }
would this not effect performance since the environment receiver will be needed for every request which essentially makes it synchronous or at the very least is vulnerable to a data race?
Just open db connection as global concurrency variable and get access to it from any function, goroutine etc.
```go
// DB is safe to be accessed from multiple goroutines
// https://golang.org/pkg/database/sql/#DB
var DBPointer, _ = sql.Open("sqlite3", "./libreread.db")
func DBTestHandler(c *gin.Context) {
rows, err := DBPointer.Query("select * from Products")
if err != nil {
panic(err)
}
defer rows.Close()
}
func main() {
r := gin.New()
r.GET("/test", DBTestHandler)
srv := &http.Server{
Handler: r,
Addr: "127.0.0.1:5050",
WriteTimeout: 15 * time.Second,
ReadTimeout: 15 * time.Second,
}
log.Fatal(srv.ListenAndServe())
}```
@McGiver- No, this is totally fine. The database object is safe to use asynchronously. And also, you should treat the struct as a holder object only / something to group your endpoints in, and not as an active data source for operations within your handler functions if that makes any sense.
Most helpful comment
@mysticmode you can put db into a custom Env type: