ใช้ Go ต่อ SQL Database
มาลองต่อผ่าน go กัน
Ref: https://pkg.go.dev/database/sql
ลง package
- package ที่เราจะใช้คือ
database/sql
ซึ่งเป็น standard library อยู่แล้ว - แต่ต้องลง driver เพื่อเป็นตัวแทนในการพูดคุยกับ PostgreSQL เพิ่ม
go get github.com/lib/pq
- ทำการต่อไปยัง PostgreSQL + handle error การ connect
package main
import (
"database/sql"
"fmt"
"log"
_ "github.com/lib/pq"
)
const (
host = "localhost" // or the Docker service name if running in another container
port = 5432 // default PostgreSQL port
user = "myuser" // as defined in docker-compose.yml
password = "mypassword" // as defined in docker-compose.yml
dbname = "mydatabase" // as defined in docker-compose.yml
)
func main() {
// Connection string
psqlInfo := fmt.Sprintf("host=%s port=%d user=%s "+
"password=%s dbname=%s sslmode=disable",
host, port, user, password, dbname)
// Open a connection
db, err := sql.Open("postgres", psqlInfo)
if err != nil {
log.Fatal(err)
}
defer db.Close()
// Check the connection
err = db.Ping()
if err != nil {
log.Fatal(err)
}
fmt.Println("Successfully connected!")
}
CRUD ผ่าน Go
ทำพื้นฐาน function CRUD (ย้าย query มาทำผ่าน Go)
สิ่งที่ปกติเราต้องทำคือ
- สร้าง function สำหรับคุยกับ SQL ในแต่ละเคสโดยส่งผ่านตัวแปร
sql.DB
เป็นตัวแทนในการพูดคุย - (optional) ประกาศ Struct ที่เป็นตัวแทนในการรับข้อมูล
ตัวอย่าง
- CRUD Function
Create
func createProduct(db *sql.DB, name string, price int, category string, quantity int) (int, error) {
var id int
err := db.QueryRow(`INSERT INTO products(name, price, category, quantity) VALUES($1, $2, $3, $4) RETURNING id;`, name, price, category, quantity).Scan(&id)
if err != nil {
return 0, err
}
return id, nil
}
Read
type Product struct {
ID int
Name string
Price int
Category string
Quantity int
}
func getProduct(db *sql.DB, id int) (Product, error) {
var p Product
row := db.QueryRow(`SELECT id, name, price, category, quantity FROM products WHERE id = $1;`, id)
err := row.Scan(&p.ID, &p.Name, &p.Price, &p.Category, &p.Quantity)
if err != nil {
return Product{}, err
}
return p, nil
}
Update
func updateProduct(db *sql.DB, id int, name string, price int, category string, quantity int) error {
_, err := db.Exec(`UPDATE products SET name = $1, price = $2, category = $3, quantity = $4 WHERE id = $5;`, name, price, category, quantity, id)
return err
}
Delete
func deleteProduct(db *sql.DB, id int) error {
_, err := db.Exec(`DELETE FROM products WHERE id = $1;`, id)
return err
}
Note
Exec
= เป็น method ที่ใช้สำหรับการ execute SQL โดยไม่มีการ return rows กลับคืนมา (เช่นINSERT
,UPDATE
,DELETE
)QueryRow
= เป็น method ที่ใช้สำหรับ query SQL เพื่อดึงข้อมูลกลับมา (เป็นข้อมูลตัวเดียว) ปกติจะใช้กับตระกูลของSELECT
Read - หลาย Item
ต้องใช้คำสั่ง Query
ในการดึงข้อมูล
Query
คือคำสั่งที่ใช้สำหรับการดึงข้อมูลแบบหลาย rows (ในกรณีที่เรา expected ว่า Query นั้นได้ข้อมูลมามากกว่า 1 rows) ซึ่งปกติ จะใช้กับตระกูลของSELECT
type Product struct {
ID int
Name string
Price int
Category string
Quantity int
}
func getProducts(db *sql.DB) ([]Product, error) {
rows, err := db.Query("SELECT id, name, price, category, quantity FROM products")
if err != nil {
return nil, err
}
defer rows.Close()
var products []Product
for rows.Next() {
var p Product
err := rows.Scan(&p.ID, &p.Name, &p.Price, &p.Category, &p.Quantity)
if err != nil {
return nil, err
}
products = append(products, p)
}
// Check for errors from iterating over rows
if err = rows.Err(); err != nil {
return nil, err
}
return products, nil
}
เพิ่มเติม
- defer คือ คำสั่งที่จะทำงานก่อนคำสั่งสุดท้ายใน program (หรือ function นั้นๆ) โดยปกติมันจะใช้สำหรับคำสั่ง cleanup เพื่อปิด process ให้ครบก่อนที่จะหยุดทำงาน