using mysql with go lang

Write at 2017 May 17 in notes hugo haproxy ssl letencrypt

We’ll start with the most popular one: “github.com/go-sql-driver/mysql”.

First, let’s create a package to handle/maintain connection.

package db

import (
	"database/sql"
	_ "github.com/go-sql-driver/mysql"
	"time"
)

var Conn *sql.DB

func init() {
	var err error
	Conn, err = sql.Open("mysql", "db")
	checkErr(err)

	Conn.SetMaxOpenConns(10)
	Conn.SetMaxIdleConns(10)
	Conn.SetConnMaxLifetime(time.Duration(1800) * time.Second)
}

func checkErr(err error) {
	if err != nil {
		panic(err)
	}
}

Now we can create a handler to query it:

type Row struct (
	ID `json:"id"`
	Name `json:"name"`
)

func Find(q string) {
	var rows []*Rows

	rows, err := db.Conn.Query(q)
	if err != nil {
		return nil, err
	}

	for rows.Next() {
		a := Row{}
		rows.Scan(&a.ID, &a.Name)
		advices = append(advices, &a)
	}
	rows.Close()
}

However, after awhile with Benchmark, I realize the performanc wasn’t that great.

Let’s enter https://github.com/gocraft/dbr. DBR promise to give better perfomance.

Optionally, we can hook into its with a event logger for metric instrument

package db

import (
	"log"
)

type ELog struct {
}

// Event receives a simple notification when various events occur
func (n *ELog) Event(eventName string) {
	log.Println(eventName)
}

// EventKv receives a notification when various events occur along with
// optional key/value data
func (n *ELog) EventKv(eventName string, kvs map[string]string) {
	log.Println(eventName, kvs)
}

// EventErr receives a notification of an error if one occurs
func (n *ELog) EventErr(eventName string, err error) error {
	log.Println(eventName, err)
	return err
}

// EventErrKv receives a notification of an error if one occurs along with
// optional key/value data
func (n *ELog) EventErrKv(eventName string, err error, kvs map[string]string) error {
	return err
}

// Timing receives the time an event took to happen
func (n *ELog) Timing(eventName string, nanoseconds int64) {
	log.Println(eventName, " take ", nanoseconds)
}

// TimingKv receives the time an event took to happen along with optional key/value data
func (n *ELog) TimingKv(eventName string, nanoseconds int64, kvs map[string]string) {
	log.Println(eventName, " take ", nanoseconds, kvs)
}

This does nothing fancy but log the time so we can easily do benchmark in dev modes as a quick and dirty way.

Let’s get started with dbr. We almost keep the same thing. Just switch to dbr.

package db

import (
	//"database/sql"
	_ "github.com/go-sql-driver/mysql"
	"github.com/gocraft/dbr"
	"time"
)

var Conn *dbr.Connection
var elog ELog

func init() {
	var err error
	elog = ELog{}
	Conn, err = dbr.Open("mysql", "db", &elog)
	checkErr(err)

	Conn.SetMaxOpenConns(80)
	Conn.SetMaxIdleConns(80)
	Conn.SetConnMaxLifetime(time.Duration(1800) * time.Second)
}

func GetDbSession() *dbr.Session {
	return Conn.NewSession(nil)
}

func checkErr(err error) {
	if err != nil {
		panic(err)
	}
}

The important thing here is despite of switching to dbr, we still need to import the driver.

Now we can run any queries:

type Row Struct {
  Foo string
  Bar string
}

var rows []*Row
var sess = db.Conn.NewSession(nil)
sess.SelectBySql("SELECT foo, bar from table").LoadStructs(&rows)