gorm是一個使用Go語言編寫的ORM框架。文檔齊全,對開發者友好,支持主流數據庫。
我最近在補齊Go語言各類基礎的框架和操作庫的知識,終於進展到了數據庫階段,搜資料的時候基本都是推薦這個框架,可見其之流行程度。在不斷嘗試練習之后,總結了一些經驗和使用方式,供初學者參考。
在之前使用Java語言的時候用過兩種JDBC和mybatis,一種是本地操作數據庫的一種是在Springboot項目中使用,兩者使用習慣上都是基於MySQL語句,都是在操作層面把MySQL語句拼寫完成。但是在gorm框架中幾乎看不到完整的SQL語句,都是通過方法和參數
go.mod
github.com/jinzhu/gorm v1.9.16
在執行Go Mod Tidy
的時候會把相關需要的依賴(這個用詞可能不准)自動添加到mod文件中。
go.mod
我現在也不是很熟悉,我也是抄能力發動+IDE提示完成的,通常來說比較順利。
我的代碼中依賴如下:
import (
"fmt"
"funtester/base"
"funtester/futil"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
"log"
"testing"
"time"
)
初始化
這個演示Demo,內容偏基礎,高階的我也不會用,目前也用不到。演示分兩類:初始化連接,初始化數據庫。由於gorm自帶了數據庫初始化功能,會將Model
對應數據庫表創建(這個需要手動開啟),所以這個在測試中還是比較常用的,如果輔以數據初始化的方法,基本滿足我們日常開發測試服務的需求。
func init() {
var err error
drive, err = gorm.Open("mysql", "root:root123456@(localhost:3306)/funtester?charset=utf8&parseTime=true")
if err != nil {
fmt.Println(err)
log.Fatalln("mysql conntect err")
}
drive.DB().SetMaxOpenConns(200)
drive.DB().SetConnMaxLifetime(10 * time.Second)
drive.DB().SetConnMaxIdleTime(10 * time.Second)
drive.DB().SetMaxIdleConns(20)
// 遷移 schema
drive.AutoMigrate(&Funtester{})
//注意: AutoMigrate 會創建表,缺少的外鍵,約束,列和索引,並且會更改現有列的類型(如果其大小、精度、是否為空可更改)。但 不會 刪除未使用的列,以保護您的數據。
//db.AutoMigrate(&User{}, &Product{}, &Order{})
//drive.Set("gorm:table_options", "ENGINE=InnoDB").AutoMigrate(&Funtester{})//帶參數的遷移
}
Model
type Funtester struct {
gorm.Model
Name string
Age int
}
這里分享一下MySQL數據庫表結構:
DROP TABLE IF EXISTS `funtesters`;
CREATE TABLE `funtesters` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`age` int unsigned DEFAULT NULL,
`created_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`created_at` datetime DEFAULT NULL,
`updated_at` datetime DEFAULT NULL,
`deleted_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_funtesters_deleted_at` (`deleted_at`)
) ENGINE=InnoDB AUTO_INCREMENT=241861 DEFAULT CHARSET=utf8mb3;
SET FOREIGN_KEY_CHECKS = 1;
這里應該就比較清晰看到gorm初始化數據庫的時候的邏輯了。這里分享一下gorm.Model
源碼:
type Model struct {
ID uint `gorm:"primary_key"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt *time.Time `sql:"index"`
}
select
下面演示一下select常用語法,這里分成了兩個:一個偏基礎,一個偏復雜(主要是多查詢條件串聯)。這里可以很明顯看出gorm拼接查詢條件的思路,就是把查詢條件分類然后單獨寫不同的條件,由gorm框架做SQL語句的拼接。
func TestSelect1(t *testing.T) {
var f Funtester
drive.First(&f, 34)//默認id
last := drive.Last(&f, "age != 1")//添加條件
fmt.Printf("查詢到記錄數 %d "+base.LINE, last.RowsAffected)
fmt.Println(f)
take := drive.Take(&f) //不指定順序
fmt.Println(take.RowsAffected)
}
// TestSelect2
// @Description: 常用查詢和處理結果
// @param t
func TestSelect2(t *testing.T) {
var fs []Funtester
var f Funtester
drive.Where("id = ?", 45).First(&f)//另外一種寫法
//fmt.Println(f)
find := drive.Where("name like ?", "fun%").Find(&fs).Limit(10).Order("id")//多查詢條件串聯
rows, _ := find.Rows()//獲取結果
defer rows.Close()
for rows.Next() {
var ff Funtester
drive.ScanRows(rows, &ff)
fmt.Println(ff.Age, ff.Name)
}
//另外一種寫法
var f1 Funtester
drive.Where("name LIKE ?", "fun").Or("id = ?", 123).First(&f1)
fmt.Println(f1)
}
update
有了select
的基礎,再來看update
就比較容易了。
// TestUpdate
// @Description: 更新
// @param t
func TestUpdate(t *testing.T) {
drive.Model(&Funtester{}).Where("id = ?", 241860).Update("name", base.FunTester+"3")
}
insert
gorm官文文檔支持批量插入的,但是這個依賴包中並沒有相關支持。各位如果使用跟我一樣的依賴的話,
// TestInsert
// @Description: 增加
// @param t
func TestInsert(t *testing.T) {
value := &Funtester{Name: "FunTester" + futil.RandomStr(10)}
drive.Create(value)
drive.Select("name", "age").Create(value) //只創建name和age字段的值
futil.Sleep(1)
drive.Omit("age", "name").Create(&Funtester{Name: "fds",Age: 122}) //過濾age和name字段創建
fs := []Funtester{{Name: "fs" + futil.RandomStr(10), Age: 12}, {Name: "fs" + futil.RandomStr(10), Age: 12}}
drive.Create(&fs)//這里不支持這么操作的
}
delete
刪除操作跟以上兩種操作使用方式一致。
func TestDelete(t *testing.T) {
db := drive.Where("id = ?", 241859).Delete(&Funtester{})
fmt.Println(db.RowsAffected)
}
執行SQL
當然gorm也是支持直接執行SQL語句的,有一個特殊就是執行查詢語句的時候需要解析查詢結果。
// TestSql
// @Description: 直接執行SQL
// @param t
func TestSql(t *testing.T) {
var funtester []Funtester
scan := drive.Raw("select * from funtesters where id > 333 limit 10").Scan(&funtester)
fmt.Println(scan.RowsAffected)
fmt.Println(funtester)
}
事務&回滾
在gorm高級語法的使用中,我覺得這個是非常實用的,對於一些測試語句的執行非常適合。
// TestRollBack
// @Description: 事務&回滾
// @param t
func TestRollBack(t *testing.T) {
funtester := Funtester{Name: base.FunTester, Age: 32232}
begin := drive.Begin()
err := begin.Create(&funtester).Error
if err != nil {
begin.Rollback()
}
begin.Commit()
}
gorm的基本使用已經分享完了,下次分享使用gorm做性能測試的實踐。