まだモデルコードを手で叩いて、go-zeroコードの自動生成を体験してみましょう!


go-zeroから原文を調べる go-zeroマイクロサービスライブラリアドレスhttps://github.com/tal-tech/go-zeroをクリック
Goctl Model
goctl modelはgo-zeroの下のツールモジュールのコンポーネントの1つであり、現在mysql ddlを識別してmodel層コード生成をサポートしており、コマンドラインまたはideaプラグイン(間もなくサポートされる)によってredis cacheまたはredis cacheを持たないコードロジックを選択的に生成することができる.
クイックスタート
  • ddl生成
    goctl model mysql ddl -src="./sql/user.sql" -dir="./sql/model" -c=true
    により上記コマンドを実行すると、CURDコードをすばやく生成することができる.
    model
    │   ├── error.go
    │   └── usermodel.go
  • datasource生成
    goctl model mysql datasource -url="user:password@tcp(127.0.0.1:3306)/database" -table="table1,table2"  -dir="./model"
  • 生成コード例
      package model
    
      import (
          "database/sql"
          "fmt"
          "strings"
          "time"
    
          "github.com/tal-tech/go-zero/core/stores/cache"
          "github.com/tal-tech/go-zero/core/stores/sqlc"
          "github.com/tal-tech/go-zero/core/stores/sqlx"
          "github.com/tal-tech/go-zero/core/stringx"
          "github.com/tal-tech/go-zero/tools/goctl/model/sql/builderx"
      )
    
      var (
          userFieldNames          = builderx.FieldNames(&User{})
          userRows                = strings.Join(userFieldNames, ",")
          userRowsExpectAutoSet   = strings.Join(stringx.Remove(userFieldNames, "id", "create_time", "update_time"), ",")
          userRowsWithPlaceHolder = strings.Join(stringx.Remove(userFieldNames, "id", "create_time", "update_time"), "=?,") + "=?"
    
          cacheUserMobilePrefix = "cache#User#mobile#"
          cacheUserIdPrefix     = "cache#User#id#"
          cacheUserNamePrefix   = "cache#User#name#"
      )
    
      type (
          UserModel struct {
              sqlc.CachedConn
              table string
          }
    
          User struct {
              Id         int64     `db:"id"`
              Name       string    `db:"name"`     //     
              Password   string    `db:"password"` //     
              Mobile     string    `db:"mobile"`   //    
              Gender     string    `db:"gender"`   //  | |   
              Nickname   string    `db:"nickname"` //     
              CreateTime time.Time `db:"create_time"`
              UpdateTime time.Time `db:"update_time"`
          }
      )
    
      func NewUserModel(conn sqlx.SqlConn, c cache.CacheConf, table string) *UserModel {
          return &UserModel{
              CachedConn: sqlc.NewConn(conn, c),
              table:      table,
          }
      }
    
      func (m *UserModel) Insert(data User) (sql.Result, error) {
          query := `insert into ` + m.table + `(` + userRowsExpectAutoSet + `) value (?, ?, ?, ?, ?)`
          return m.ExecNoCache(query, data.Name, data.Password, data.Mobile, data.Gender, data.Nickname)
      }
    
      func (m *UserModel) FindOne(id int64) (*User, error) {
          userIdKey := fmt.Sprintf("%s%v", cacheUserIdPrefix, id)
          var resp User
          err := m.QueryRow(&resp, userIdKey, func(conn sqlx.SqlConn, v interface{}) error {
              query := `select ` + userRows + ` from ` + m.table + ` where id = ? limit 1`
              return conn.QueryRow(v, query, id)
          })
          switch err {
          case nil:
              return &resp, nil
          case sqlc.ErrNotFound:
              return nil, ErrNotFound
          default:
              return nil, err
          }
      }
    
      func (m *UserModel) FindOneByName(name string) (*User, error) {
          userNameKey := fmt.Sprintf("%s%v", cacheUserNamePrefix, name)
          var resp User
          err := m.QueryRowIndex(&resp, userNameKey, func(primary interface{}) string {
              return fmt.Sprintf("%s%v", cacheUserIdPrefix, primary)
          }, func(conn sqlx.SqlConn, v interface{}) (i interface{}, e error) {
              query := `select ` + userRows + ` from ` + m.table + ` where name = ? limit 1`
              if err := conn.QueryRow(&resp, query, name); err != nil {
                  return nil, err
              }
              return resp.Id, nil
          }, func(conn sqlx.SqlConn, v, primary interface{}) error {
              query := `select ` + userRows + ` from ` + m.table + ` where id = ? limit 1`
              return conn.QueryRow(v, query, primary)
          })
          switch err {
          case nil:
              return &resp, nil
          case sqlc.ErrNotFound:
              return nil, ErrNotFound
          default:
              return nil, err
          }
      }
    
      func (m *UserModel) FindOneByMobile(mobile string) (*User, error) {
          userMobileKey := fmt.Sprintf("%s%v", cacheUserMobilePrefix, mobile)
          var resp User
          err := m.QueryRowIndex(&resp, userMobileKey, func(primary interface{}) string {
              return fmt.Sprintf("%s%v", cacheUserIdPrefix, primary)
          }, func(conn sqlx.SqlConn, v interface{}) (i interface{}, e error) {
              query := `select ` + userRows + ` from ` + m.table + ` where mobile = ? limit 1`
              if err := conn.QueryRow(&resp, query, mobile); err != nil {
                  return nil, err
              }
              return resp.Id, nil
          }, func(conn sqlx.SqlConn, v, primary interface{}) error {
              query := `select ` + userRows + ` from ` + m.table + ` where id = ? limit 1`
              return conn.QueryRow(v, query, primary)
          })
          switch err {
          case nil:
              return &resp, nil
          case sqlc.ErrNotFound:
              return nil, ErrNotFound
          default:
              return nil, err
          }
      }
    
      func (m *UserModel) Update(data User) error {
          userIdKey := fmt.Sprintf("%s%v", cacheUserIdPrefix, data.Id)
          _, err := m.Exec(func(conn sqlx.SqlConn) (result sql.Result, err error) {
              query := `update ` + m.table + ` set ` + userRowsWithPlaceHolder + ` where id = ?`
              return conn.Exec(query, data.Name, data.Password, data.Mobile, data.Gender, data.Nickname, data.Id)
          }, userIdKey)
          return err
      }
    
      func (m *UserModel) Delete(id int64) error {
          data, err := m.FindOne(id)
          if err != nil {
              return err
          }
          userIdKey := fmt.Sprintf("%s%v", cacheUserIdPrefix, id)
          userNameKey := fmt.Sprintf("%s%v", cacheUserNamePrefix, data.Name)
          userMobileKey := fmt.Sprintf("%s%v", cacheUserMobilePrefix, data.Mobile)
          _, err = m.Exec(func(conn sqlx.SqlConn) (result sql.Result, err error) {
              query := `delete from ` + m.table + ` where id = ?`
              return conn.Exec(query, id)
          }, userIdKey, userNameKey, userMobileKey)
          return err
      }
  • 使用法
    goctl model mysql -h
    NAME:
       goctl model mysql - generate mysql model"
    
    USAGE:
       goctl model mysql command [command options] [arguments...]
    
    COMMANDS:
       ddl         generate mysql model from ddl"
       datasource  generate model from datasource"
    
    OPTIONS:
       --help, -h  show help

    ルールの生成
  • デフォルト・ルール私たちのデフォルト・ユーザーは、テーブルの作成時にcreateTime、updateTimeフィールド(大文字と小文字を無視し、下線の命名スタイル)を作成し、デフォルト値はCURRENT_TIMESTAMPですが、updateTimeはON UPDATE CURRENT_TIMESTAMPをサポートしています.この2つのフィールドに対してinsertupdateが生成されると削除され、付与の範疇内ではありません.もちろん、この2つのフィールドが必要でない場合は大丈夫です.
  • 帯域キャッシュモード
  • ddl
    goctl model mysql -src={filename} -dir={dir} -cache=true
  • datasource
    goctl model mysql datasource -url={datasource} -table={tables}  -dir={dir} -cache=true


  • 現在はredisキャッシュのみがサポートされています.帯域キャッシュモードを選択すると、生成されたFindOne(ByXxx)&Deleteコードはキャッシュロジック付きのコードを生成します.現在は単一インデックスフィールド(全文インデックスを除く)のみがサポートされています.連合インデックスについてはデフォルトではキャッシュは必要なく、汎用コードではないと考えられています.そのため、exampleのuserテーブルのidnamemobileフィールドは、いずれも単一フィールドインデックスに属します.
  • キャッシュモードなし
  • ddl
    goctl model -src={filename} -dir={dir}
  • datasource
        goctl model mysql datasource -url={datasource} -table={tables}  -dir={dir}


  • or
  • ddl
      goctl model -src={filename} -dir={dir} -cache=false
  • datasource
      goctl model mysql datasource -url={datasource} -table={tables}  -dir={dir} -cache=false

  • 生成コードは基本的なCURD構造のみである.
    キャッシュ
    キャッシュについては、一問一答の形式で羅列することを選びました.これによりmodelでキャッシュされる機能をより明確に記述できると思います.
  • キャッシュにはどのような情報がキャッシュされますか?プライマリ・キー・フィールドのキャッシュでは、構造体情報全体がキャッシュされ、単一インデックス・フィールド(全文インデックスを除く)ではプライマリ・キー・フィールド値がキャッシュされます.
  • データの更新(update)操作はキャッシュを空にしますか?はい、しかし、プライマリ・キー・キャッシュの情報だけを空にします.why?ここでは詳しくは述べない.
  • なぜ単一インデックスフィールドに従ってupdateByXxxおよびdeleteByXxxのコードを生成しないのですか?理論的には問題ありませんが、modelレイヤのデータ操作は、クエリーを含む構造体全体を単位としていると考えられています.フィールドの一部だけをクエリーすることをお勧めしません(反対しません).そうしないと、キャッシュは意味がありません.
  • なぜfindPageLimitfindAllのようなモードコード生成層をサポートしないのですか?現在、基本的なCURD以外のコードはすべて業務型コードだと思いますが、これは開発者が業務の必要に応じて作成したほうがいいと思います.