» Go: Build a REST API with Gin » 2. Development » 2.6 Database: MySQL

Database: MySQL

SQLite here is for demonstration only. If you want a more production-ready database, try MySQL or mongoDB.

Switch to MySQL

  1. Install MySQL on your machine and start it.

Note: Remember to create indexes on tables based on your need in a production project.

  1. Add gorm's mysql dependency:
go get -u gorm.io/driver/mysql
  1. Update code.

Add infrastructure/database/mysql.go:

/*
Package database does all db persistence implementations.
*/
package database

import (
	"context"

	"gorm.io/driver/mysql"
	"gorm.io/gorm"

	"literank.com/rest-books/domain/model"
)

type MySQLPersistence struct {
	db *gorm.DB
}

func NewMySQLPersistence(dsn string) (*MySQLPersistence, error) {
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		return nil, err
	}
	// Auto Migrate the data structs
	db.AutoMigrate(&model.Book{})

	return &MySQLPersistence{db}, nil
}

func (s *MySQLPersistence) CreateBook(ctx context.Context, b *model.Book) (uint, error) {
	if err := s.db.WithContext(ctx).Create(b).Error; err != nil {
		return 0, err
	}
	return b.ID, nil
}

func (s *MySQLPersistence) UpdateBook(ctx context.Context, id uint, b *model.Book) error {
	var book model.Book
	if err := s.db.WithContext(ctx).First(&book, id).Error; err != nil {
		return err
	}
	return s.db.WithContext(ctx).Model(book).Updates(b).Error
}

func (s *MySQLPersistence) DeleteBook(ctx context.Context, id uint) error {
	return s.db.WithContext(ctx).Delete(&model.Book{}, id).Error
}

func (s *MySQLPersistence) GetBook(ctx context.Context, id uint) (*model.Book, error) {
	var book model.Book
	if err := s.db.WithContext(ctx).First(&book, id).Error; err != nil {
		return nil, err
	}
	return &book, nil
}

func (s *MySQLPersistence) GetBooks(ctx context.Context) ([]*model.Book, error) {
	books := make([]*model.Book, 0)
	if err := s.db.WithContext(ctx).Find(&books).Error; err != nil {
		return nil, err
	}
	return books, nil
}

Notice that the key difference is that we use mysql.Open(dsn) instead of sqlite.Open(fileName) in gorm.Open(mysql.Open(dsn), &gorm.Config{}).

DSN stands for Data Source Name. It's a string that provides the necessary information for an application to connect to a specific database instance.

Add DSN config item into the DBConfig struct in infrastructure/config/config.go:

 type DBConfig struct {
        FileName string `json:"file_name" yaml:"file_name"`
+       DSN      string `json:"dsn" yaml:"dsn"`
 } 

Update WireHelper to switch the dependency in application/wire_helper.go:

@@ -8,11 +8,11 @@ import (
 
 // WireHelper is the helper for dependency injection
 type WireHelper struct {
-       persistence *database.SQLitePersistence
+       persistence *database.MySQLPersistence
 }
 
 func NewWireHelper(c *config.Config) (*WireHelper, error) {
-       db, err := database.NewSQLitePersistence(c.DB.FileName)
+       db, err := database.NewMySQLPersistence(c.DB.DSN)
        if err != nil {
                return nil, err
        }

Put in a DSN value in main.go:

@@ -15,6 +15,7 @@ func main() {
                },
                DB: config.DBConfig{
                        FileName: "test.db",
+                       DSN:      "test_user:test_pass@tcp(127.0.0.1:3306)/lr_book?charset=utf8mb4&parseTime=True&loc=Local",
                },
        }
        // Prepare dependencies

Voila! Your api server is powered by MySQL now!

PrevNext