一、简介
1.1 go-pg是什么
官网描述为Golang ORM with focus on PostgreSQL features and performance
一个专注于 PostgreSQL 特性和性能的 Golang ORM。
如果你已经厌倦了手动写查询语句,那么可以尝试下go-pg框架来编写业务代码。
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 多维数组使用 array tag and Array wrapper.(重点) -
hstore使用 hstore tag and Hstore wrapper.(重点) -
组合类型Composite types. -
默认情况下,所有结构字段都默认为空,并且零值(空字符串、0、零时间、空map映射或切片、nil 指针)被编组为 SQL“NULL”。 pg:",notnull"
标签用户添加SQL 非空约束。pg:",use_zero"
标签允许Go零值. -
Transactions. -
Prepared statements. -
Notifications using LISTEN
andNOTIFY
. -
拷贝数据 使用 COPY FROM
andCOPY 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 EXPLAIN
to 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.从接口体来创建数据库表 -
ForEach that calls a function for each row returned by the query without loading all rows into the memory.
1.3 优缺点
1.优点
1.没有rows.Close去手动管理连接
在go-pg中,无需为每个打开的连接进行rows.Close操作。
2.go-pg比其他GORM性能更好
go-pg本身就很专注于性能这块。
3.go-pg自动将行数据映射为go的结构体和slice切片
4.go-pg 生成更高效的连接查询
与其他 ORM 甚至数据库包相比,您可以对连接进行高效查询。
5.简化你的代码
go-pg使用一个函数去编写语句,所以能简化你的代码。
6.提升开发效率
这是我们在项目中考虑使用ORM的首要原因。使用go-pg你无需手动的编写sql语句,所以可以加快你的开发效率。
2.缺点
1.Time.Time UTC转换
像 created_at、updated_at 这样的时间将转换为 UTC() ,所以如果你想使用时区,你必须添加你的时区。
2.此ORM仅限于postgre
二 、部署安装和建库
首先确保你已经安装了postgresql数据库,其安装和入门操作教程可参考https://www.runoob.com/postgresql/postgresql-tutorial.html。go-pg 支持 2 个最新的 Go 版本,并且需要一个支持模块的 Go 版本。
安装 pg/v10(注意导入中的 v10;省略它是一个常见的错误):
go get github.com/go-pg/pg/v10
手动创建数据库
CREATE DATABASE 命令需要在 PostgreSQL 命令窗口来执行:
CREATE DATABASE test;
此处我创建了一个名称为test的数据库,用来学习go-pg框架
三、CURD操作示例
3.1 连接数据库
db := pg.Connect(&pg.Options{
Addr: ":5432",
User: "user",
Password: "pass",
Database: "db_name",
})
Addr:数据库地址,需替换成你自己的postgresql数据库地址
User:用户名,需替换成你自己的用户名
Password:密码,需替换成你自己的密码
Database:要连接的数据库名称,,需替换成你自己的数据库名称
另一种更流行的方式是采用连接字符串
opt, err := pg.ParseURL("postgres://user:pass@localhost:5432/db_name")
if err != nil {
panic(err)
}
db := pg.Connect(opt)
3.2 创建表
创建数据库表的函数为CreateTable,函数参数为CreateTableOptions类型的指针,下面一起来看下CreateTableOptions结构体。
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的数据类型text
Temp:临时的
IfNotExists:如果不存在则创建
FKConstraints:添加创建外键的约束
示例代码如下所示:
//通过定义的结构体来创建数据库表
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 删除表
创建数据库表的函数为DropTable,函数参数为DropTableOptions类型的指针,下面一起来看下DropTableOptions结构体。
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
此处演示代码为查询全部记录
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数据库地址
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.连接数据库
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
}
//莫忘记关闭数据库连接
defer func(pgsqlDB *pg.DB) {
err := pgsqlDB.Close()
if err != nil {
fmt.Println("close postgresql failed")
}
}(pgsqlDB)
//3.创建表
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
}
//通过结构体来删除表
func deleteSchema(db *pg.DB) error{
models := []interface{}{
(*User)(nil),
}
err := db.Model(&models).DropTable(&orm.DropTableOptions{
IfExists: true,
Cascade: true,
})
return err
}
//通过定义的结构体来创建数据库表
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中国社区:https://gocn.vip/
《酷Go推荐》招募:
各位Gopher同学,最近我们社区打算推出一个类似GoCN每日新闻的新栏目《酷Go推荐》,主要是每周推荐一个库或者好的项目,然后写一点这个库使用方法或者优点之类的,这样可以真正的帮助到大家能够学习到
新的库,并且知道怎么用。
大概规则和每日新闻类似,如果报名人多的话每个人一个月轮到一次,欢迎大家报名!戳「阅读原文」,即可报名
扫码也可以加入 GoCN 的大家族哟~
文章评论