百億數據百億花, 庫若恆河沙復沙,Go lang1.18入門精鍊教程,由白丁入鴻儒,Go lang數據庫操作實踐EP12

  • 2022 年 8 月 18 日
  • 筆記

Golang可以通過Gorm包來操作數據庫,所謂ORM,即Object Relational Mapping(數據關係映射),說白了就是通過模式化的語法來操作數據庫的行對象或者表對象,對比相對靈活繁複的SQL語句,ORM上手簡單,通用性較高,但是在性能層面略有損耗,Gorm的底層是結構體對象,關於結構體,請移玉步至:你有對象類,我有結構體,Go lang1.18入門精鍊教程,由白丁入鴻儒,go lang結構體(struct)的使用EP06

Gorm的安裝與配置

首先如果要使用Gorm操作數據庫,得先有數據庫才行,這裡為了全平台統一標準,我們使用Docker來安裝Mysql數據庫,Docker的安裝請參見:一寸宕機一寸血,十萬容器十萬兵|Win10/Mac系統下基於Kubernetes(k8s)搭建Gunicorn+Flask高可用Web集群,運行命令運行mysql容器:

docker run --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root -d mysql:8.0.19

注意這裡如果宿主機已經有Mysql服務了,需要將:左邊的端口號錯開,改成3307或者其他什麼端口。

隨後在終端運行命令安裝Gorm包:

go get -u github.com/jinzhu/gorm

這裡-u參數的意思是為當前用戶安裝,並不局限於某個項目。

隨後安裝Mysql數據庫鏈接驅動包:

go get -u github.com/go-sql-driver/mysql

接着在任意位置編寫test.go腳本:

package main  
  
import (  
	"fmt"  
	"github.com/jinzhu/gorm"  
	_ "github.com/jinzhu/gorm/dialects/mysql"  
)  
  
func main() {  
	db, err := gorm.Open("mysql", "root:root@(localhost)/mytest?charset=utf8mb4&parseTime=True&loc=Local")  
  
	if err != nil {
                fmt.Println(err)
       		fmt.Println("連接數據庫出錯")  
		return  
	}  
  
	defer db.Close()
        fmt.Println("鏈接Mysql成功")  
}

這裡導入輸出包和Gorm包,同時通過下劃線的形式導入mysql驅動包,這樣做的好處是mysql驅動的init()函數會在被導入時執行,因為我們並不需要驅動包的具體模塊或者函數,而僅僅是用它連一下數據庫而已。

隨後,創建結構體變量db,注意Open函數對應的Mysql參數是否正確。

注意,結構體變量賦值過程中如果報錯,需要判斷err變量內容,並且使用return關鍵字提前結束邏輯,關於golang的錯誤處理,可參見:人非聖賢孰能無過,Go lang1.18入門精鍊教程,由白丁入鴻儒,Go lang錯誤處理機制EP11

最後,使用defer關鍵字在所有邏輯執行後關閉Mysql數據庫鏈接。

編譯執行後,程序返回:

鏈接Mysql成功

當然Gorm並不僅僅只能操作Mysql,其他主流數據庫也都支持,比方說Sqllite3,事實上,在成本有限或者緩存體系比較完備的情況下,Sqllite3完全可以替代Mysql,首先安裝sqllite3驅動:

go get -u github.com/jinzhu/gorm/dialects/sqlite

然後修改test.go文件:

package main  
  
import (  
	"fmt"  
  
	"github.com/jinzhu/gorm"  
	//_ "github.com/jinzhu/gorm/dialects/mysql"  
	_ "github.com/jinzhu/gorm/dialects/sqlite"  
)  
  
func main() {  
	//db, err := gorm.Open("mysql", "root:root@(localhost)/mytest?charset=utf8mb4&parseTime=True&loc=Local")  
  
	db, err := gorm.Open("sqlite3", "/tmp/gorm.db")  
  
	if err != nil {  
		fmt.Println(err)  
		fmt.Println("連接數據庫出錯")  
		return  
	}  
  
	defer db.Close()  
  
	fmt.Println("鏈接sqllite3成功")  
}

編譯執行後返回:

鏈接sqllite3成功

數據庫操作

連接好數據庫之後,我們就可以做一些數據庫層面的操作了,比如程序層面的數據庫遷移操作:

// 文章信息  
type ArticleInfo struct {  
	ID     uint  
	Title  string  
	Author string  
}

這裡建立文章表的結構體數據,隨後編寫遷移邏輯:

//數據遷移  
db.AutoMigrate(&ArticleInfo{})  
fmt.Println("表創建成功")

進入Mysql命令行,輸入命令:

MySQL [(none)]> use mytest;  
Database changed  
MySQL [mytest]> desc article_infos  
    -> ;  
+--------+------------------+------+-----+---------+----------------+  
| Field  | Type             | Null | Key | Default | Extra          |  
+--------+------------------+------+-----+---------+----------------+  
| id     | int(10) unsigned | NO   | PRI | NULL    | auto_increment |  
| title  | varchar(255)     | YES  |     | NULL    |                |  
| author | varchar(255)     | YES  |     | NULL    |                |  
+--------+------------------+------+-----+---------+----------------+  
3 rows in set (0.03 sec)  
  
MySQL [mytest]>

沒有問題。

創建數據:

a1 := ArticleInfo{1, "iris", "iris"}  
a2 := ArticleInfo{2, "iris", "女"}  
// 創建記錄  
db.Create(&a1)  
db.Create(&a2)

這裡我們聲明兩個結構體變量,然後將其指針傳遞給db變量的Create函數,編譯運行後,鍵入命令進行查詢操作:

MySQL [mytest]> select * from article_infos\g  
+----+-------+--------+  
| id | title | author |  
+----+-------+--------+  
|  1 | iris  | iris   |  
|  2 | iris  | 女     |  
+----+-------+--------+

隨後,將剛才入庫的數據查詢出來:

// 查詢  
a := new(ArticleInfo)  
db.First(a)  
fmt.Println(a)

這裡通過new關鍵字初始化結構體,然後使用First函數獲取第一條記錄。

程序返回:

鏈接mysql成功  
&{1 iris iris}

查出來的結構體指針可以直接用來做修改操作:

// 查詢  
	a := new(ArticleInfo)  
	db.First(a)  
	fmt.Println(a)  
  
	//修改  
	db.Model(&a).Update("Author", "123")  
  
	fmt.Println(a)

程序返回:

鏈接mysql成功  
&{1 iris iris}  
&{1 iris 123}

非常方便。

最後,是刪除操作:

// 刪除  
db.Delete(&a)

這裡通過指針傳入Delete函數即可:

MySQL [mytest]> select * from article_infos\g  
+----+-------+--------+  
| id | title | author |  
+----+-------+--------+  
|  2 | iris  | 女     |

該條記錄已經被物理刪除。

執行原生SQL

如果我們需要執行原生的sql語句,Gorm也提供了對應的函數:

var articles []ArticleInfo  
//   查詢 執行用Scan 和Find 一樣  
db = db.Raw("select * from article_infos ").Scan(&articles)  
fmt.Println(articles)

這裡只需要聲明文章的結構體變量,然後執行Scan函數即可:

[{2 iris 女} {3 iris iris} {4 iris 女}]

這裡會返回一個切片嵌套結構體的結果集。

除此之外,更新和刪除操作:

//  更新和刪除.插入用 Exec  
db = db.Exec("update article_infos set author='123' where id = 2")  
fmt.Println("更新了", db.RowsAffected, "條數據")  
db = db.Exec("delete from article_infos where id=4")  
fmt.Println("更新了", db.RowsAffected, "條數據")

程序返回:

[]main.ArticleInfo更新了 1 條數據  
更新了 1 條數據

結語

目前Golang的比較流行的ORM包除了Gorm,還有Xorm,對比Python數據庫ORM的百花齊放,百家爭鳴,Go lang還有很長的一段路需要走,真實環境下的數據庫操作也不僅僅是增刪改查,更多操作請移步Gorm官方文檔://gorm.io/zh_CN/docs/