GORM trong Golang

Điều kiện cần:

  • Đã làm việc với CSDL quan hệ
  • Đã lập trình kết nối với Hệ quản trị CSDL (MySQL, MS SQL Server,...)
  • Đã biết đến ORM

Giới thiệu về GORM

GORM là thư viện ORM tuyệt vời cho Golang để xử lý với quan hệ cơ sở dữ liệu. Thư viện GORM được phát triển trên các gói (package) database/SQL.

Các tính năng của GORM là:

  • Hỗ trợ đầy đủ các tính năng của ORM
  • Liên kết: có một (Has One), có nhiều (Has Many), thuộc (Belongs To), nhiều nhiều (Many To Many), Đa hình (Polymorphism), Bảng đơn kế thừa (Single-table inheritance)
  • Hook: trước/sau (Before/After), Tạo/Lưu/Cập nhật/Xoá/Tìm kiếm (Create/Save/Update/Delete/Find)
  • Hỗ trợ nhiều thao tác tải: Tải trước, Nối
  • Giao dịch, Giao dịch lồng nhau, điểm lưu trữ giao dịch (Save Point), Huỷ giao dịch đến điểm đã lưu trữ
  • Ngữ cảnh, chuẩn bị chế độ trạng thái, chế độ chạy DryRun
  • Chèn hàng loạt, tìm hàng loạt, Tìm / Tạo với Bản đồ, CRUD với các câu lệnh SQL và trình xác thực ngữ cảnh
  • Trình tạo SQL, Nâng cấp, khoá, Tối ưu hoá / chỉ mục / gợi ý nhận xét, đối số được đặt tên, truy vấn con
  • Khoá chính kết hợp, chỉ mục, ràng buộc
  • Tự động lưu trú
  • Bộ ghi nhật ký tự động (Logger)
  • API cắm vào linh hoạt, có thể mở rộng
  • Mọi tính năng đều đi kèm với kiểm thử
  • Thân thiện với Lập trình viên

Cài đặt thư viện GORM

Để cài đặt thư viện GORM, chúng ta sử dụng lệnh sau:

go get -u gorm.io/gorm

Để cài đặt thêm các trình điều khiển với các hệ quản trị CSDL khác nhau chúng ta sử dụng những lệnh sau:

  • SQLite
    go get -u gorm.io/driver/sqlite​
  • MySQL
    go get -u gorm.io/driver/mysql​
  • PostgreSQL
    go get -u gorm.io/driver/postgres​
  • SQL Server
    go get -u gorm.io/driver/sqlserver​

Kiểm tra kết nối với CSDL

main.go

package main

import (
	"fmt"

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

func main() {
	dsn := "sinhnx:sinhnx.dev@tcp(127.0.0.1:3306)/OrderDB?charset=utf8mb4&parseTime=True&loc=Local"
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
    if err != nil {
        panic("failed to connect database")
    } else {
        fmt.Println("Connect Successfull.")
	}
}

gorm.Model

GORM định nghĩa gorm.Model là một cấu trúc (struct), bao gồm các trường:

  • ID: là khoá chính 
  • CreatedAt: thời gian tạo
  • UpdatedAt: thời gian cập nhật
  • DeletedAt: thời gian xoá
// gorm.Model definition
type Model struct {
  ID        uint           `gorm:"primaryKey"`
  CreatedAt time.Time
  UpdatedAt time.Time
  DeletedAt gorm.DeletedAt `gorm:"index"`
}

Khai báo mô hình (Models)

Model sử dụng kiểu struct bình thường, con trỏ hoặc tương tự hoặc kiểu tuỳ chọn thực thi 2 interface Scanner và Valuer.

Ví dụ:

type User struct {
  ID           uint
  Name         string
  Email        *string
  Age          uint8
  Birthday     *time.Time
  MemberNumber sql.NullString
  ActivedAt    sql.NullTime
  CreatedAt    time.Time
  UpdatedAt    time.Time
}

GORM ưu tiên quy ước hơn cấu hình, theo mặc định, GORM sử dụng ID làm khóa chính, tên cấu trúc làm tên bảng, các trường làm tên cột và sử dụng CreatedAt, UpdatedAt để theo dõi thời gian tạo / cập nhật.

Nếu bạn tuân theo các quy ước đã được GORM thông qua, bạn sẽ cần viết rất ít cấu hình / mã lệnh. Nếu quy ước không phù hợp với yêu cầu của bạn, GORM cho phép bạn cấu hình lại chúng

Cấp quyền cho các trường

Các trường mặc định đã có tất cả quyền khi thực hiện CRUD với GORM và GORM cho phép bạn thay đổi quyền cấp trường với thẻ, vì vậy bạn có thể đặt một trường ở chế độ chỉ đọc, chỉ ghi, chỉ tạo, chỉ cập nhật hoặc bỏ qua

Lưu ý: các trường bị bỏ qua sẽ không được tạo khi sử dụng GORM Migrator để tạo bảng

type User struct {
  Name string `gorm:"<-:create"` // allow read and create
  Name string `gorm:"<-:update"` // allow read and update
  Name string `gorm:"<-"`        // allow read and write (create and update)
  Name string `gorm:"<-:false"`  // allow read, disable write permission
  Name string `gorm:"->"`        // readonly (disable write permission unless it configured )
  Name string `gorm:"->;<-:create"` // allow read and create
  Name string `gorm:"->:false;<-:create"` // createonly (disabled read from db)
  Name string `gorm:"-"`  // ignore this field when write and read
}

Theo dõi tời gian Tạo/Cập nhật theo giây (Milli / Nano)

GORM sử dụng trường CreatedAt, UpdatedAt để theo dõi thời gian tạo / cập nhật theo quy ước và GORM sẽ đặt thời gian hiện tại khi tạo / cập nhật nếu các trường được xác định

Để sử dụng các trường có tên khác, bạn có thể định cấu hình các trường đó bằng thẻ autoCreateTime, autoUpdateTime

Nếu bạn muốn lưu thời gian thành giây UNIX (milli / nano) thay vì thời gian, bạn có thể chỉ cần thay đổi kiểu dữ liệu của trường theo thời gian int

type User struct {
  CreatedAt time.Time // Set to current time if it is zero on creating
  UpdatedAt int       // Set to current unix seconds on updaing or if it is zero on creating
  Updated   int64 `gorm:"autoUpdateTime:nano"` // Use unix nano seconds as updating time
  Updated   int64 `gorm:"autoUpdateTime:milli"`// Use unix milli seconds as updating time
  Created   int64 `gorm:"autoCreateTime"`      // Use unix seconds as creating time
}

Cấu trúc lồng nhau

Đối với các trường ẩn danh, GORM sẽ bao gồm các trường của nó vào cấu trúc cha của nó, ví dụ:

type User struct {
  gorm.Model
  Name string
}
// equals
type User struct {
  ID        uint           `gorm:"primaryKey"`
  CreatedAt time.Time
  UpdatedAt time.Time
  DeletedAt gorm.DeletedAt `gorm:"index"`
  Name string
}

Đối với trường cấu trúc bình thường, bạn có thể nhúng trường đó bằng thẻ được nhúng, ví dụ:

type Author struct {
  Name  string
  Email string
}

type Blog struct {
  ID      int
  Author  Author `gorm:"embedded"`
  Upvotes int32
}
// equals
type Blog struct {
  ID    int64
  Name  string
  Email string
  Upvotes  int32
}

Và bạn có thể sử dụng thẻ embeddedPrefix để thêm tiền tố vào tên CSDL của trường được nhúng, ví dụ:

type Blog struct {
  ID      int
  Author  Author `gorm:"embedded;embeddedPrefix:author_"`
  Upvotes int32
}
// equals
type Blog struct {
  ID          int64
  AuthorName  string
  AuthorEmail string
  Upvotes     int32
}

Thẻ gán của trường

Các thẻ là tùy chọn để sử dụng khi khai báo mô hình, GORM hỗ trợ các thẻ sau: Thẻ không phân biệt chữ hoa chữ thường và quy ước bướu lạc đà (camelCase) được ưu tiên hơn.

Tên thẻ Mô tả
column tên cột trong CSDL
type kiểu dữ liệu của cột sử dụng kiểu chung tương thích. Ví dụ: bool, int, uint, float, string, time, byte, hoạt động trên tất cả các cơ sở dữ liệu và có thể được sử dụng với các thẻ khác cùng nhau, như not null, size, autoIncrement… kiểu dữ liệu cơ sở dữ liệu được chỉ định như varbinary(8) cũng được hỗ trợ, khi sử dụng kiểu dữ liệu cơ sở dữ liệu được chỉ định, nó cần phải là kiểu dữ liệu cơ sở dữ liệu đầy đủ. Ví dụ: MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT
size xác định kích thước/chiều dài của cột dữ liệu
primaryKey xác định khoá chính
unique xác định ràng buộc duy nhất
default xác định ràng buộc giá trị mặc định
precision xác định độ chính xác của cột
scale xác định cột có khả năng co dãn
not null xác định cột không được phép null
autoIncrement xác định cột tăng tự động (kiểu int)
embedded gắn với trường
embeddedPrefix xác định tiền tố cho tên cột được gán vào trường
autoCreateTime Theo dõi thời gian hiện tại khi tạo. Đối với các trường kiểu int thì nó sẽ lưu trữ giây theo hệ UNIX sử dụng giá trị theo nano/mili giây. Ví dụ: autoCreateTime: nano
autoUpdateTime Theo dõi thời gian hiện tại khi cập nhật. Đối với các trường kiểu int thì nó sẽ lưu trữ giây theo hệ UNIX sử dụng giá trị theo nano/mili giây. Ví dụ: autoCreateTime: nano
index tạo chỉ mục với các tuỳ chọn, sử dụng tên giống với các trường được tạo với việc tạo các chỉ mục kết hợp
uniqueIndex tương tự như index, nhưng tạo ra chỉ mục duy nhất
check tạo ràng buộc check. Ví dụ check:age > 13
<- Phân quyền ghi cho trường.
<-:create phân quyền chỉ tạo
<-:update phân quyền chỉ cập nhật
<-:false không có quyền ghi
<- phân quyền tạo và cập nhật
-> Phân quyền đọc cho trường
->:false không cho phép đọc
- bỏ qua trường này, không cho phép đọc/ghi
foreignKey Xác định Khoá ngoại
references Xác định tham chiếu
polymorphic Xác định kiểu đa dạng
polymorphicValue Xác định giá trị đa dạng, mặc định tên bảng
many2many Xác định tên bảng nối
joinForeignKey Xác định khoá ngoại của bảng nối
joinReferences Xác định tham chiếu khoá ngoại của bảng nối
constraint Ràng buộc quan hệ. VD: trong lúc cập nhật (OnUpdate), trong lúc xoá (OnDelete)