8

I try to set up mysql database in golang.
I created db.go for mysql setting up and import it to main.go.
But when I run main.go, error occurs because of db.go.
I want to resolve this error.

There is no compile error.
But when running go run main.go, error occurs.

main.go

package main

// import

func main() {
    err := godotenv.Load()
    if err != nil {
    }
    db := db.NewDatabase(os.Getenv("MYSQL_USER"), os.Getenv("MYSQL_PASSWORD"), os.Getenv("MYSQL_HOST"))
    s3 := s3.NewS3(os.Getenv("AWS_ACCESS_KEY_ID"), os.Getenv("AWS_SECRET_ACCESS_KEY"))
    dao := dao.NewDao(db.DATABASE, s3)
    service := service.NewService(dao)
    cntlr := controller.NewController(service)

    router := gin.Default()

    router.Use(cors.New(cors.Config{
        AllowOrigins:     []string{"*"},
        AllowMethods:     []string{"GET", "POST", "OPTIONS"},
        AllowHeaders:     []string{"Content-Type", "Content-Length", "Accept-Encoding", "X-CSRF-Token", "Authorization", "accept", "origin", "Cache-Control", "X-Requested-With"},
        ExposeHeaders:    []string{"Content-Length"},
        AllowCredentials: true,
        AllowOriginFunc: func(origin string) bool {
            return true
        },
        MaxAge: 15 * time.Second,
    }))

    api := router.Group("/api")
    {
        api.GET("/articles", func(c *gin.Context) {
            cntlr.GetArticleController(c)
        })
        api.GET("/article/:id", func(c *gin.Context) {
            cntlr.GetSingleArticleController(c)
        })
        api.GET("/delete/:id", func(c *gin.Context) {
            cntlr.DeleteArticleController(c)
        })
        api.POST("/post", func(c *gin.Context) {
            cntlr.PostController(c)
        })
        api.POST("/post/image", func(c *gin.Context) {
            cntlr.PostImageController(c)
        })
        api.POST("/post/image/db", func(c *gin.Context) {
            cntlr.PostImageToDBController(c)
        })
    }

    router.Run(":2345")
}

db.go

package db

import "database/sql"

type Database struct {
    MYSQL_USER     string
    MYSQL_PASSWORD string
    MYSQL_HOST     string
    DATABASE       *sql.DB
}

func NewDatabase(user, password, host string) *Database {
    db, err := sql.Open("mysql", user+":"+password+"@tcp("+host+":3306)/article")
    if err != nil {
        panic(err.Error())
    }

    defer db.Close()

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

    _, err = db.Exec("CREATE DATABASE IF NOT EXISTS article;")
    if err != nil {
        panic(err)
    }

    _, err = db.Exec("use article;")
    if err != nil {
        panic(err)
    }

    _, err = db.Exec("CREATE TABLE IF NOT EXISTS `articles` (`id` int NOT NULL AUTO_INCREMENT PRIMARY KEY,uuid varchar(36), `title` VARCHAR(100) NOT NULL,`content` TEXT NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8;")
    if err != nil {
        panic(err)
    }

    _, err = db.Exec("create table IF NOT EXISTS images (id int AUTO_INCREMENT NOT NULL PRIMARY KEY, article_uuid varchar(36), image_name varchar(50)); ")
    if err != nil {
        panic(err)
    }
    Database := new(Database)
    Database.DATABASE = db
    return Database
}

Here is full source code(branch: refactor-db):
https://github.com/jpskgc/article/tree/refactor-db

I expect there is no error when running go run main.go.
But the actual is not.
There will be some problem around db.go.

Here is the error message.

GET /api/articles HTTP/1.1
Host: localhost:2345
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Cache-Control: max-age=0
Connection: keep-alive
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36


sql: database is closed
/Users/jpskgc/article/api/dao/dao.go:36 (0x1553240)
        (*Dao).GetArticleDao: panic(err.Error())
/Users/jpskgc/article/api/service/service.go:34 (0x17a9abb)
        Service.GetArticleService: results := s.dao.GetArticleDao()
/Users/jpskgc/article/api/controller/controller.go:19 (0x17cd664)
        Controller.GetArticleController: articles := controller.service.GetArticleService()
/Users/jpskgc/article/api/main.go:79 (0x17cec1f)
        main.func2: cntlr.GetArticleController(c)
/Users/jpskgc/go/pkg/mod/github.com/gin-gonic/[email protected]/context.go:124 (0x1791e89)
        (*Context).Next: c.handlers[c.index](c)
/Users/jpskgc/go/pkg/mod/github.com/gin-gonic/[email protected]/recovery.go:83 (0x17a5159)
        RecoveryWithWriter.func1: c.Next()
/Users/jpskgc/go/pkg/mod/github.com/gin-gonic/[email protected]/context.go:124 (0x1791e89)
        (*Context).Next: c.handlers[c.index](c)
/Users/jpskgc/go/pkg/mod/github.com/gin-gonic/[email protected]/logger.go:240 (0x17a4200)
        LoggerWithConfig.func1: c.Next()
/Users/jpskgc/go/pkg/mod/github.com/gin-gonic/[email protected]/context.go:124 (0x1791e89)
        (*Context).Next: c.handlers[c.index](c)
/Users/jpskgc/go/pkg/mod/github.com/gin-gonic/[email protected]/gin.go:389 (0x179b6a1)
        (*Engine).handleHTTPRequest: c.Next()
/Users/jpskgc/go/pkg/mod/github.com/gin-gonic/[email protected]/gin.go:351 (0x179aed3)
        (*Engine).ServeHTTP: engine.handleHTTPRequest(c)
/usr/local/go/src/net/http/server.go:2774 (0x12e2a07)
        serverHandler.ServeHTTP: handler.ServeHTTP(rw, req)
/usr/local/go/src/net/http/server.go:1878 (0x12de5f0)
        (*conn).serve: serverHandler{c.server}.ServeHTTP(w, w.req)
/usr/local/go/src/runtime/asm_amd64.s:1337 (0x1059ea0)
        goexit: BYTE    $0x90   // NOP

[GIN] 2019/09/10 - 16:58:46 | 500 |    5.990926ms |             ::1 | GET      /api/articles
3
  • 7
    You're calling defer db.Close() inside NewDatabase. Don't do that if you don't want your db closed when NewDatabase returns. You don't need to close the db if you plan on reusing it. However you need to close rows whenever you call Query, otherwise your app will hit the connection limit and crash. Commented Sep 10, 2019 at 9:53
  • Thanks for suggestion. Issue is resolved. Commented Sep 10, 2019 at 10:31
  • AllowCredentials: true and AllowOriginFunc: func(origin string) bool { return true } is a recipe for disaster in terms of Web security. Commented Jul 22, 2021 at 19:29

1 Answer 1

20

Just remove defer db.Close() in db.go You need to close connection out of NewDatabase method

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.