酷Go推荐 postgresql ORM 框架 go-pg

haolipeng12345 · 2021年08月03日 · 114 次阅读

一、简介

1、1 go-pg 是什么

官网描述为 Golang ORM with focus on PostgreSQL features and performance

一个专注于 PostgreSQL 特性和性能的 Golang ORM。

如果你已经厌倦了手动写查询语句,那么可以尝试下 go-pg 框架来编写业务代码。

1、2 特性

1、3 优缺点

1、优点

1、没有 rows.Close 去手动管理连接

在 go-pg 中,无需为每个打开的连接进行 rows.Close 操作。

2、go-pg 比其他 GORM 性能更好

go-pg 本身就很专注于性能这块。

3、go-pg 自动将行数据映射为 go 的结构体和 slice 切片

4、go-pg 生成更高效的连接查询

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.htmlgo-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{"1078285863@qq.com"},
    },
    {
        Name: "haolipeng",
        Emails: []string{"haolipeng12345@163.com"},
    },
}
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{"haolipeng@antiy.cn"},
}
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)
}

type Story struct {
   Id       int64
   Title    string
   AuthorId int64
   Author   *User `pg:"rel:has-one"`
}

func (s Story) String() string {
   return fmt.Sprintf("Story<%d %s %s>", s.Id, s.Title, s.Author)
}

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{"1078285863@qq.com"},
      },
      {
         Id: 3,
         Name: "haolipeng",
         Emails: []string{"haolipeng12345@163.com"},
      },
   }
   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{"haolipeng@antiy.cn"},
   }
   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
}

参考资料

https://pg.uptrace.dev/

https://medium.com/tunaiku-tech/go-pg-golang-postgre-orm-2618b75c0430

更多原创文章干货分享,请关注公众号
  • 加微信实战群请加微信(注明:实战群):gocnio
暂无回复。
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册