MySQL

查詢單筆

package main

import (
	"database/sql"
	"fmt"

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

func main() {
	db, err := sql.Open("mysql", "root:example@/USERS")
	if err != nil {
		panic(err.Error())
	}
	defer db.Close()
	
	rows, err := db.Query("SELECT name FROM user")
	if err != nil {
		panic(err.Error()) // proper error handling instead of panic in your app
	}
	var name string
	err = rows.Scan(&name)
	fmt.Println(name)
}

或是

var userName string
sqlStmt := `SELECT account FROM user WHERE account = ? AND password = ?`
err := db.QueryRow(sqlStmt, user.Account, user.Password).Scan(&userName)
if err != nil {
  panic(err.Error()) // proper error handling instead of panic in your app
}

宣告一個變數,之後傳變數的地址給 rows.Scan

查詢多筆

	app.Get("message", func(c *fiber.Ctx) {
		rows, err := db.Query("SELECT from_person, to_person, create_time FROM message WHERE from_person=?", "Eason")
		if err != nil {
			log.Fatalln(err)
		}
		for rows.Next() {
			var fromPerson string
			var toPerson string
			var createTime string
			err = rows.Scan(&fromPerson, &toPerson, &createTime)
			if err != nil {
				log.Fatalln(err)
			}
			fmt.Println(fromPerson, toPerson, createTime)
		}
		rows.Close()
	})

或是使用 struct

type Message struct {
	FromPerson string
	ToPerson   string
	Content    string
	CreateTime string
}
	
	app.Get("message", func(c *fiber.Ctx) {
		rows, err := db.Query("SELECT from_person, to_person, content, create_time FROM message WHERE from_person=?", "Eason")
		if err != nil {
			log.Fatalln(err)
		}
		for rows.Next() {
			message := new(Message)
			err = rows.Scan(&message.FromPerson, &message.ToPerson, &message.Content, &message.CreateTime)
			if err != nil {
				log.Fatalln(err)
			}
			// return struct
			fmt.Println(message)
		}
		rows.Close()
	})

或是

package main

import (
	"database/sql"
	"fmt"

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

func main() {

	db, err := sql.Open("mysql", "root:example@/USERS")
	if err != nil {
		panic(err.Error())
	}
	defer db.Close()

	rows, err := db.Query("SELECT * FROM user")
	if err != nil {
		panic(err.Error()) // proper error handling instead of panic in your app
	}
	columns, err := rows.Columns()
	if err != nil {
		panic(err.Error()) // proper error handling instead of panic in your app
	}

	// Make a slice for the values
	values := make([]sql.RawBytes, len(columns))

	// rows.Scan wants '[]interface{}' as an argument, so we must copy the
	// references into such a slice
	// See http://code.google.com/p/go-wiki/wiki/InterfaceSlice for details
	scanArgs := make([]interface{}, len(values))
	for i := range values {
		scanArgs[i] = &values[i]
	}

	// Fetch rows
	for rows.Next() {
		// get RawBytes from data
		err = rows.Scan(scanArgs...)
		if err != nil {
			panic(err.Error()) // proper error handling instead of panic in your app
		}

		// Now do something with the data.
		// Here we just print each column as a string.
		var value string
		for i, col := range values {
			// Here we can check if the value is nil (NULL value)
			if col == nil {
				value = "NULL"
			} else {
				value = string(col)
			}
			fmt.Println(columns[i], ": ", value)
		}
		fmt.Println("-----------------------------------")
	}
	if err = rows.Err(); err != nil {
		panic(err.Error()) // proper error handling instead of panic in your app
	}

}

確認資料是否存在

func UserExists(db *sql.DB, account string) bool {
	sqlStmt := `SELECT account FROM user WHERE account = ?`
	err := db.QueryRow(sqlStmt, account).Scan(&account)
	if err != nil {
		if err != sql.ErrNoRows {
			log.Print(err)
		}
		return false
	}
	return true
}

插入資料

package main

import (
	"database/sql"
	"fmt"
	"log"
	"net/http"

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

func dbConn() (db *sql.DB) {
	dbDriver := "mysql"
	dbUser := "root"
	dbPass := "example"
	dbName := "USERS"
	db, err := sql.Open(dbDriver, dbUser+":"+dbPass+"@/"+dbName)
	if err != nil {
		panic(err.Error())
	}
	return db
}

func insert(w http.ResponseWriter, r *http.Request) {
	log.Println("onRequest")
	db := dbConn()
	if r.Method == "POST" {
		r.ParseForm()
		name := r.FormValue("name")
		city := r.FormValue("city")
		insForm, err := db.Prepare("INSERT INTO employee(name, city) VALUES(?,?)")
		if err != nil {
			panic(err.Error())
		}
		insForm.Exec(name, city)
		log.Println("INSERT: Name: " + name + " | City: " + city)
	}
	defer db.Close()
	http.Redirect(w, r, "/", 301)
}

func main() {
	log.Println("Server started on: http://localhost:8050")
	http.HandleFunc("/insert", insert)
	http.ListenAndServe(":8050", nil)
}

更新資料

	app.Post("/updateUser", func(c *fiber.Ctx) {
		user := new(User)
		if err := c.BodyParser(user); err != nil {
			log.Fatal(err)
		}
		insForm, err := db.Prepare("UPDATE user SET name=?, city=? WHERE id=?")
		if err != nil {
			panic(err.Error())
		}
		fmt.Println(user)
		_, err = insForm.Exec(user.Name, user.City, user.ID)
		if err != nil {
			panic(err.Error())
		}
		c.JSON(fiber.Map{"status": "ok"})
	})

將 整個資料庫備份 產生 table SCHEMA 與 insert statement

https://dev.mysql.com/doc/refman/8.0/en/mysqldump.html

可使用 mysqldump,如果在 docker 內要使用如下指令。

docker exec <docker id> //usr/bin/mysqldump -u root --password=example --routines --triggers <DB名稱> > ~/test_db_backup.sql

也可使用 mysqlpump

可能錯誤

1.通常為 schema 與資料不同,或是給的長度不夠

panic: runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation code=0x1 addr=0x18 pc=0x143b97e]

Last updated