<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【GoCN酷Go推薦】postgresql ORM 框架 go-pg系列(一)

          共 14292字,需瀏覽 29分鐘

           ·

          2021-08-11 11:10

          一、簡介

          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 LISTEN and NOTIFY.
          • 拷貝數(shù)據(jù) 使用 COPY FROM and COPY 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.從接口體來創(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 的大家族喲~





          瀏覽 37
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  人妻热色 | 先锋音影自拍偷拍 | 99在线视频在线 | 床戏麻豆| 久久人妻狠狠操 |