【GoCN酷Go推薦】postgresql ORM 框架 go-pg系列(一)
一、簡介
1.1 go-pg是什么
官網(wǎng)描述為Golang ORM with focus on PostgreSQL features and performance
一個專注于 PostgreSQL 特性和性能的 Golang ORM。
如果你已經(jīng)厭倦了手動寫查詢語句,那么可以嘗試下go-pg框架來編寫業(yè)務代碼。
1.2 特性
基礎類型: integers, floats, string, bool, time.Time, net.IP, net.IPNet. sql.NullBool, sql.NullString, sql.NullInt64, sql.NullFloat64 and pg.NullTime. sql.Scanner and sql/driver.Valuer interfaces. Structs, maps and arrays 默認序列化為json格式. PostgreSQL 多維數(shù)組使用 array tag and Array wrapper.(重點) hstore使用 hstore tag and Hstore wrapper.(重點) 組合類型Composite types. 默認情況下,所有結(jié)構(gòu)字段都默認為空,并且零值(空字符串、0、零時間、空map映射或切片、nil 指針)被編組為 SQL“NULL”。 pg:",notnull"標簽用戶添加SQL 非空約束。pg:",use_zero"標簽允許Go零值.Transactions. Prepared statements. Notifications using LISTENandNOTIFY.拷貝數(shù)據(jù) 使用 COPY FROMandCOPY TO.Timeouts and canceling queries using context.Context. Automatic connection pooling with circuit breaker support. Queries retry on network errors. Working with models using ORM and SQL. Scanning variables using ORM and SQL. SelectOrInsert using on-conflict. INSERT ... ON CONFLICT DO UPDATE using ORM. Bulk/batch inserts, updates, and deletes. Common table expressions using WITH and WrapWith. CountEstimate using EXPLAINto get estimated number of matching rows.ORM 框架支持 has one, belongs to, has many, and many to many with composite/multi-column primary keys. Soft deletes. Creating tables from structs.從接口體來創(chuàng)建數(shù)據(jù)庫表 ForEach that calls a function for each row returned by the query without loading all rows into the memory.
1.3 優(yōu)缺點
1.優(yōu)點
1.沒有rows.Close去手動管理連接
在go-pg中,無需為每個打開的連接進行rows.Close操作。
2.go-pg比其他GORM性能更好
go-pg本身就很專注于性能這塊。
3.go-pg自動將行數(shù)據(jù)映射為go的結(jié)構(gòu)體和slice切片
4.go-pg 生成更高效的連接查詢
與其他 ORM 甚至數(shù)據(jù)庫包相比,您可以對連接進行高效查詢。
5.簡化你的代碼
go-pg使用一個函數(shù)去編寫語句,所以能簡化你的代碼。
6.提升開發(fā)效率
這是我們在項目中考慮使用ORM的首要原因。使用go-pg你無需手動的編寫sql語句,所以可以加快你的開發(fā)效率。
2.缺點
1.Time.Time UTC轉(zhuǎn)換
像 created_at、updated_at 這樣的時間將轉(zhuǎn)換為 UTC() ,所以如果你想使用時區(qū),你必須添加你的時區(qū)。
2.此ORM僅限于postgre
二 、部署安裝和建庫
首先確保你已經(jīng)安裝了postgresql數(shù)據(jù)庫,其安裝和入門操作教程可參考https://www.runoob.com/postgresql/postgresql-tutorial.html。go-pg 支持 2 個最新的 Go 版本,并且需要一個支持模塊的 Go 版本。
安裝 pg/v10(注意導入中的 v10;省略它是一個常見的錯誤):
go get github.com/go-pg/pg/v10
手動創(chuàng)建數(shù)據(jù)庫
CREATE DATABASE 命令需要在 PostgreSQL 命令窗口來執(zhí)行:
CREATE DATABASE test;
此處我創(chuàng)建了一個名稱為test的數(shù)據(jù)庫,用來學習go-pg框架
三、CURD操作示例
3.1 連接數(shù)據(jù)庫
db := pg.Connect(&pg.Options{
Addr: ":5432",
User: "user",
Password: "pass",
Database: "db_name",
})
Addr:數(shù)據(jù)庫地址,需替換成你自己的postgresql數(shù)據(jù)庫地址
User:用戶名,需替換成你自己的用戶名
Password:密碼,需替換成你自己的密碼
Database:要連接的數(shù)據(jù)庫名稱,,需替換成你自己的數(shù)據(jù)庫名稱
另一種更流行的方式是采用連接字符串
opt, err := pg.ParseURL("postgres://user:pass@localhost:5432/db_name")
if err != nil {
panic(err)
}
db := pg.Connect(opt)
3.2 創(chuàng)建表
創(chuàng)建數(shù)據(jù)庫表的函數(shù)為CreateTable,函數(shù)參數(shù)為CreateTableOptions類型的指針,下面一起來看下CreateTableOptions結(jié)構(gòu)體。
type CreateTableOptions struct {
Varchar int // replaces PostgreSQL data type `text` with `varchar(n)`
Temp bool
IfNotExists bool
// FKConstraints causes CreateTable to create foreign key constraints
// for has one relations. ON DELETE hook can be added using tag
// `pg:"on_delete:RESTRICT"` on foreign key field. ON UPDATE hook can be added using tag
// `pg:"on_update:CASCADE"`
FKConstraints bool
}
Varchar:用varchar(n)來替代postgresql的數(shù)據(jù)類型text
Temp:臨時的
IfNotExists:如果不存在則創(chuàng)建
FKConstraints:添加創(chuàng)建外鍵的約束
示例代碼如下所示:
//通過定義的結(jié)構(gòu)體來創(chuàng)建數(shù)據(jù)庫表
func createSchema(db *pg.DB) error {
models := []interface{}{
(*User)(nil),
}
for _, model := range models {
err := db.Model(model).CreateTable(&orm.CreateTableOptions{
//Temp: true,//建表是臨時的
IfNotExists: true,
})
if err != nil {
return err
}
}
return nil
}
3.3 刪除表
創(chuàng)建數(shù)據(jù)庫表的函數(shù)為DropTable,函數(shù)參數(shù)為DropTableOptions類型的指針,下面一起來看下DropTableOptions結(jié)構(gòu)體。
type DropTableOptions struct {
IfExists bool
Cascade bool
}
IfExists:如果存在則刪除
示例代碼如下所示:
func deleteSchema(db *pg.DB) error{
models := []interface{}{
(*User)(nil),
}
err := db.Model(&models).DropTable(&orm.DropTableOptions{
IfExists: true,
Cascade: true,
})
return err
}
3.4 查詢 Select
此處演示代碼為查詢?nèi)坑涗?/p>
var queryResult []User
err = pgsqlDB.Model(&queryResult).Select()
if err != nil{
goto ERR
}
fmt.Printf("query result:%v",queryResult)
3.5 添加 Insert
插入單行記錄
//4.插入一條記錄
user1 = &User{
Name: "admin",
Emails: []string{"admin1@admin", "admin2@admin"},
}
result, err = pgsqlDB.Model(user1).Insert()
if err != nil {
goto ERR
}
fmt.Printf("single insert rows affected:%d",result.RowsAffected())
插入多行記錄
userList = []User{
{
Name: "haolipeng",
Emails: []string{"[email protected]"},
},
{
Name: "haolipeng",
Emails: []string{"[email protected]"},
},
}
result,err = pgsqlDB.Model(&userList).Insert()
if err != nil{
goto ERR
}
fmt.Printf("single insert rows affected:%d",result.RowsAffected())
3.6 刪除 Delete
刪除id為2的記錄
delUser = User{
Id: 2,
}
result,err = pgsqlDB.Model(&delUser).WherePK().Delete()
if err != nil{
goto ERR
}
fmt.Printf("delete rows affected:%d\n",result.RowsAffected())
3.7 修改 Update
//修改除主鍵外的其他列
updateUser = User{
Id: 1,
Name: "antiy",
Emails: []string{"[email protected]"},
}
result,err = pgsqlDB.Model(&updateUser).WherePK().Update()
if err != nil{
goto ERR
}
fmt.Printf("update rows affected:%d\n",result.RowsAffected())
四、完整代碼
setting.go文件
package conf
const (
DbAddr = "10.240.19.200:5432" //postgresql數(shù)據(jù)庫地址
User = "postgres"
Password = "123456"
DbName = "test"
UseConnectionString = false
)
main.go文件
package main
import (
"errors"
"fmt"
"github.com/go-pg/pg/v10"
"github.com/go-pg/pg/v10/orm"
"github.com/haolipeng/go-pg-example/conf"
)
type User struct {
Id int64
Name string
Emails []string
}
func (u User) String() string {
return fmt.Sprintf("User<%d %s %v>", u.Id, u.Name, u.Emails)
}
func main() {
var (
err error
pgsqlDB *pg.DB = nil
result pg.Result
user1 *User
updateUser User
delUser User
userList []User
queryResult []User
)
//1.連接數(shù)據(jù)庫
pgsqlDB = pg.Connect(&pg.Options{
Addr: conf.DbAddr,
User: conf.User,
Password: conf.Password,
Database: conf.DbName,
})
if pgsqlDB == nil{
err = errors.New("pg.Connect() failed,error:")
goto ERR
}
//莫忘記關閉數(shù)據(jù)庫連接
defer func(pgsqlDB *pg.DB) {
err := pgsqlDB.Close()
if err != nil {
fmt.Println("close postgresql failed")
}
}(pgsqlDB)
//3.創(chuàng)建表
err = createSchema(pgsqlDB)
if err != nil {
goto ERR
}
//4.插入一條記錄
user1 = &User{
Id: 1,
Name: "admin",
Emails: []string{"admin1@admin", "admin2@admin"},
}
result, err = pgsqlDB.Model(user1).Insert()
if err != nil {
goto ERR
}
fmt.Printf("single insert rows affected:%d\n",result.RowsAffected())
//5.批量插入多條記錄
userList = []User{
{
Id: 2,
Name: "haolipeng",
Emails: []string{"[email protected]"},
},
{
Id: 3,
Name: "haolipeng",
Emails: []string{"[email protected]"},
},
}
result,err = pgsqlDB.Model(&userList).Insert()
if err != nil{
goto ERR
}
fmt.Printf("batch insert rows affected:%d\n",result.RowsAffected())
//6.查詢
err = pgsqlDB.Model(&queryResult).Select()
if err != nil{
goto ERR
}
fmt.Printf("query result:%v\n",queryResult)
//7.修改
//修改除主鍵外的其他列
updateUser = User{
Id: 1,
Name: "antiy",
Emails: []string{"[email protected]"},
}
result,err = pgsqlDB.Model(&updateUser).WherePK().Update()
if err != nil{
goto ERR
}
fmt.Printf("update rows affected:%d\n",result.RowsAffected())
//8.刪除記錄(刪除id為2的記錄)
delUser = User{
Id: 2,
}
result,err = pgsqlDB.Model(&delUser).WherePK().Delete()
if err != nil{
goto ERR
}
fmt.Printf("delete rows affected:%d\n",result.RowsAffected())
//9.將當前記錄查詢并都打印出來
err = pgsqlDB.Model(&queryResult).Select()
if err != nil{
goto ERR
}
fmt.Printf("query result:%v\n",queryResult)
return
ERR:
fmt.Println("error:",err)
return
}
//通過結(jié)構(gòu)體來刪除表
func deleteSchema(db *pg.DB) error{
models := []interface{}{
(*User)(nil),
}
err := db.Model(&models).DropTable(&orm.DropTableOptions{
IfExists: true,
Cascade: true,
})
return err
}
//通過定義的結(jié)構(gòu)體來創(chuàng)建數(shù)據(jù)庫表
func createSchema(db *pg.DB) error {
models := []interface{}{
(*User)(nil),
}
for _, model := range models {
err := db.Model(model).CreateTable(&orm.CreateTableOptions{
//Temp: true,//建表是臨時的
IfNotExists: true,
})
if err != nil {
return err
}
}
return nil
}
所有示例代碼已上傳到github倉庫:
github地址:
https://github.com/haolipeng/go-pg-example
參考資料
https://pg.uptrace.dev/
https://medium.com/tunaiku-tech/go-pg-golang-postgre-orm-2618b75c0430
更多請查看:https://github.com/haolipeng/go-pg-example
歡迎加入我們GOLANG中國社區(qū):https://gocn.vip/
《酷Go推薦》招募:
各位Gopher同學,最近我們社區(qū)打算推出一個類似GoCN每日新聞的新欄目《酷Go推薦》,主要是每周推薦一個庫或者好的項目,然后寫一點這個庫使用方法或者優(yōu)點之類的,這樣可以真正的幫助到大家能夠?qū)W習到
新的庫,并且知道怎么用。
大概規(guī)則和每日新聞類似,如果報名人多的話每個人一個月輪到一次,歡迎大家報名!戳「閱讀原文」,即可報名
掃碼也可以加入 GoCN 的大家族喲~
