当前位置:网站首页>Go novice exploration road 2

Go novice exploration road 2

2022-06-25 12:36:00 Velly_ zheng

Minor objectives of the current period

The previous section , Has been used go Realization mysql Database connection and data CRUD operation ; however , Nowadays, the actual business implementation rarely writes native sql sentence , therefore , Keep pace with the times , The small goal of this period is to use ORM The model implements the operation of the database .

go ORM Realization

1. orm plug-in unit

Compared a lot orm frame , But by contrast , I think for novices , Only master beego Self contained orm The framework is enough , Familiar with and master the self-contained orm, Then some other principles will naturally be understood .

Installation package

go get github.com/astaxie/beego/client/orm

2. Database design

Here for the convenience of later implementation , Here we begin to design a relatively complete database table

  • User table user
  • Organization chart group
  • User information sheet user_info
  • Address table address
  • Area code table address_code
  • Template table template
  • Order information sheet order_info
  • Distribution information table delivery_info
  • After sale list after_sale
  • Template snapshot table template_snapshot
  • Public field table common_field

user surface :

Name explain
id Self growth id
group_id organization id
status state , There were on off freeze
created_at Creation time
updated_at Update time
deleted_at Delete time

user_info surface :

Name explain
id Self growth id
user_id user id
user_name user name
nickname nickname
avatar_url Image address
phone cell-phone number
birth Date of birth
email mailbox
vip Whether it is vip
vip_accountvip account number
created_at Creation time
updated_at Update time

group surface :

Name explain
id Self growth id
parent_id Superior organization id
name Organization name
status The state of organization on off
created_at Creation time
updated_at Update time

address surface :

Name explain
id Self growth id
user_id user id
province Province Code
city City Code
area Area code
detail_address Detailed address
status state
created_at Creation time
updated_at Update time

address_code surface :

Name explain
id unique index id
partner_id The superior id
name province 、 City or district name
created_at Creation time
updated_at Update time

template surface :

Name explain
id Self growth id
name Template name
create_user_id Create user id
template_version Template version number
template_type Template type ,input or output
template_content Template content , object type , Containing fields id and Fill in the attribute in the field ( If required )
status state
created_at Creation time
updated_at Update time

template_snapshot surface :

Name explain
id Self growth id
template_ id Templates id
name Template name
create_user_id Create user id
template_version Template version number
template_type Template type ,input or output
template_content Template content , object type , Containing fields id and Fill in the attribute in the field ( If required )
created_at Creation time
updated_at Update time

common_field surface :

Name explain
id Self growth id
column_ type Field type ,input radio
column_name The English name of the field in the table
column_title The field displays the Chinese name
admin_id Create administrator id
status state on off
options If it is radio type , You need to write options, Add a drop-down list value to choose from Including English and Chinese names
created_at Creation time
updated_at Update time

order_info surface :

Name explain
id Self growth id
send_user_id Order user id
receive_user_id Recipient user id
send_address Addressee address
receive_address Addressee address
content Shipment item information
status The order status Not delivered Shipped
weight weight
express_company Logistics company id
expense Express fee
customer_remark User notes
shop_remark Merchant remarks
created_at Creation time
updated_at Update time

delivery_info surface :

Name explain
id Self growth id
order_id Order id
express_id courier number
status Express status In transit Sending Sign for
send_time Sending time
receive_time Pick up time
weight weight
expense Express fee
insured Is it insured
insured_amount The insured amount
remark Shipping notes
created_at Creation time
updated_at Update time

** after_sale surface :**

Name explain
id Self growth id
express_id courier number
back_express_id Courier no. of returned items
status Returning Confirm receipt
send_time Sending time
receive_time Pick up time
expense Express fee
remark Shipping notes
created_at Creation time
updated_at Update time

chart
 Insert picture description here

3. Concrete realization

In fact, the specific implementation involves more

in general , If it's easy to implement , That is, there is a direct main.go file , Write the database connection operation and database creation operation .

But such rough writing , Not suitable for work , Because no one would write that , It's so inappropriate .

Here we recommend another way to write

Use go-gormigrate/gormigrate plug-in unit , adopt migrate Corresponding to instruction generation table surface

3.1 Command execution script

 Command structure
Concrete realization :
migrate.go

package command

import (
    "ExcelHandleProject/src/config/mysql"
    "ExcelHandleProject/src/migration"
    "ExcelHandleProject/src/pkg/logger"
    "fmt"
    "github.com/go-gormigrate/gormigrate/v2"
    "github.com/spf13/cobra"
)

var migrateCmd = &cobra.Command{
    
    Use:     "migrate",
    Short: " Perform database migration ",
    Run: migrate,
}

func init()  {
    
    rootCmd.AddCommand(migrateCmd)
}

func migrate(cmd *cobra.Command, args []string)  {
    
    migrations := migration.GetMigrations()
    fmt.Printf("migrations %#v \n", migrations)

    //mList by *gormigrate.Migration type 
    for conn, mList := range migrations {
    
        //conn by admin and default,db For objects connected to the database 
        db := mysql.GormClientByConn(conn)
        m := gormigrate.New(db, gormigrate.DefaultOptions, mList)
        if err := m.Migrate(); err != nil {
    
            logger.Fatalf("Could not migrate: %v", err)
        }
    }

    logger.Printf("Migration did run successfully")
}

root.go

package command

import "github.com/spf13/cobra"

var (
    rootCmd = &cobra.Command{
    
        Use: "excel",
    }
)

func Execute() error {
    
    return rootCmd.Execute()
}

main.go

package main

import "ExcelHandleProject/cmd/command"

func main()  {
    
    _ = command.Execute()
}

perform go run cmd/main.go migrate Command to create a defined in the database model

3.2 Defined migration file

 Insert picture description here
Concrete realization :
migration.go

package migration

import (
    "ExcelHandleProject/src/config/mysql"
    "github.com/go-gormigrate/gormigrate/v2"
)

// Defining interfaces , contain SAdditionally() function 
type Migration interface {
    
    Additionally() []*gormigrate.Migration
}

// Back to the assembly 
// type  byte yes uint8 Another name for  rune  yes int32 Another name for   Representing one unicode code 
// When a variable is declared , The system automatically assigns a zero value to this type 
// Short mode := Variable definition and initialization syntax , but := Limited   Defining variables , Initialization is also displayed ; Cannot provide data type ; Can only be used inside a function 
//var It is usually used to indicate the type of variable that needs to be displayed 
func GetMigrations() map[string][]*gormigrate.Migration  {
    
    // Define initialization variables migrations
    var migrations map[string][]*gormigrate.Migration
    migrations = make(map[string][]*gormigrate.Migration)

    //mysql.Connections() return slice, The stored content is configs Under folder app.yml To configure 
    //v by default and admin
    for _, v := range mysql.Connections() {
    
        migrations[v] = append(migrations[v], NewInitialMigration().Additionally(v)...)
    }

    return migrations
}

initial_migration.go

package migration

import (
    "ExcelHandleProject/src/model"
    "github.com/go-gormigrate/gormigrate/v2"
    "gorm.io/gorm"
)

type InitialMigration struct {
    

}

func (*InitialMigration) Additionally(conn string) []*gormigrate.Migration {
    
    //switch By default case Last brought break sentence , If necessary, perform the following case, have access to fallthrough
    //go-gormigrate/gormigrate grammar  gormigrate.Migration{}
    switch conn {
    
    case "default":
        return []*gormigrate.Migration{
    
        // Here is just an example , Everyone writes other things by themselves 
            {
    
                ID: "201608301430",
                Migrate: func(tx *gorm.DB) error {
    
                    return tx.AutoMigrate(&model.User{
    })
                },
                Rollback: func(tx *gorm.DB) error {
    
                    return tx.Migrator().DropTable((&model.User{
    }).TableName())
                },
            },
        }
    default:
        return []*gormigrate.Migration{
    
        }
    }
}

// Create a InitialMigration object 
func NewInitialMigration() *InitialMigration {
    
    return new(InitialMigration)
}

3.3 Database connection implementation

 Insert picture description here
mysql.go

package mysql

import (
    "ExcelHandleProject/src/config"
    "ExcelHandleProject/src/lvm/runtime"
    "database/sql"
    "encoding/json"
    "fmt"
    _ "github.com/go-sql-driver/mysql"
    "gorm.io/driver/mysql"
    "gorm.io/gorm"
    "log"
    "time"
)

var connections []string
var connClientMapping map[string]*sql.DB

// Definition mysql Database connection parameters 
type mysqlConnectParams struct {
    
	Name      string   `json:"name"`
	Host      string   `json:"host"`
	Port      uint     `json:"port"`
	User      string   `json:"user"`
	Password  string   `json:"password"`
}

func init()  {
    
    //  call config package , Get configured map aggregate 
    // Execute first config Bag init() function , Read again app.yml In the document database.mysql To configure 
	conf := config.GetMap("database.mysql")
	//make(Type, length), Initialize a slice, perhaps map perhaps chan object , And it can only be these three objects , This is also the return value Type, Instead of Pointers ,new Return pointer 
	//slice Is an abstraction of an array  go The length of the array cannot be changed , slice Length is not fixed , You can append elements 
	// Create a collection 
    connClientMapping = make(map[string]*sql.DB)
    //returns a slice with length and capacity of 0
	connections = make([]string, 0)

	for k, v := range conf {
    
	    //json.Marshal() Serialized data 
		jByte, err := json.Marshal(v)
		if err != nil {
    
		    //%#v  Output go The value of the language grammar format 
			log.Fatal(fmt.Sprintf("parse mysql config err: %#v", err))
			return
		}

		//  Defining variables param,  The type is mysqlConnectParams
		param := mysqlConnectParams{
    }
        //json.Unmarshal() Deserialized data , take json The string is decoded to the corresponding data structure 
        err = json.Unmarshal(jByte, &param)
		if err != nil {
    
			log.Fatal(fmt.Sprintf("parse mysql config err: %#v", err))
			return
		}

		// by slice connections dynamic add elements
		connections = append(connections, k)
		// Splicing connect string,  Connect to database 
		connClientMapping[k] = connect(buildDsn(param))
	}

	fmt.Printf("connClientMappings %#v \n", connClientMapping)
}

//function The difference between lowercase and uppercase letters of names :
//  Regardless of the method name , Constant , Variable name or structure name , If the initial is capitalized , Can be accessed by other packages ; If the initials are lowercase , It can only be used in this package 
func Connections() []string {
    
	return connections
}

//gorm Connect to database ,dsn := "user:[email protected](127.0.0.1:3306)/dbname?charset=utf8&parseTime=True&loc=Local"
//parseTime=true the date or datetime like 0000-00-00 00:00:00 is converted into zero value of time.Time
// fmt.Sprintf  Format output  %s character string  %d integer 
//loc=Local set the location for time
func buildDsn(p mysqlConnectParams) string  {
    
	dsn := fmt.Sprintf("%s:%[email protected](%s:%d)/%s?charset=utf8&parseTime=true", p.User, p.Password, p.Host, p.Port, p.Name)
	return dsn
}

// For external calls 
func ClientByConn(conn string) *sql.DB {
    
	return connClientMapping[conn]
}

func GormClientByConn(conn string) *gorm.DB  {
    
	if conn == "" {
    
		return nil
	}

	//sqlDB by admin or default Database connection string 
	sqlDB := connClientMapping[conn]
	fmt.Printf("sqlDB conn %#v %#v \n", sqlDB, conn)

	//sqlDB by *sql.DB,gorm usage , Connect to database 
	gormDB, err := gorm.Open(mysql.New(mysql.Config{
    
		Conn: sqlDB,
	}), &gorm.Config{
    })

	if err != nil {
    
		panic(err)
	}

	return gormDB
}

// gorm Database connection   obtain dsn After the string 
// gorm.Open(mysql.Open(dsn), &gorm.Config{})
// database/sql Package connection to database  sql.Open("driver-name", *dsn)
func connect(dsn string) *sql.DB {
    
    // Connect to database 
	db, err := sql.Open("mysql", dsn)
	if err != nil {
    
		// Encountered an unrecoverable error , No return error, choice go die, Active trigger panic; Array out of bounds will also trigger panic
		//panic Will stop the program currently executing ( It's not just a collaborative process ), And os.Exit(-1) Dissimilarity ,panic Will process the current goroutine already defer The task that hangs up , After the execution, in 
		// Then exit the whole program 
		panic(err)
	}

	// Set the maximum length of time that the connection can be reused 3 minute 
	// signify , All connections will be created the first time 3 Minutes expired , Cannot reuse after expiration 
	// Clean up operations are automatically run once per second to remove expired connections from the pool 
	db.SetConnMaxLifetime(time.Minute * 3)
	//  Set the maximum number of concurrent connections , If 10 Connections are open and in use , And if the application needs another connection , The application will be forced to wait 
	//  until 10 One of the open connections is released as idle 
	db.SetMaxOpenConns(10)
	//  By default sql.DB A maximum of... Is allowed in the connection pool 2 Free connections 
	//  Set the maximum number of idle connections 
	//  Theoretically , Allowing more free connections in the pool will improve performance , It can reduce the possibility of establishing a connection from scratch , Help save resources 
	// maxIdleConn Should be less than or equal to maxOpenConn
	db.SetMaxIdleConns(10)

	runtime.RegisterShutdown(func ()  {
    
		_ = db.Close()
	})

	return db
}

3.4 The configuration file

 Insert picture description here
app.yml

database:
  mysql:
    default:
      name: excel
      host: localhost
      port: 3306
      user: ***
      password: ***

4. Pay attention to problems

This code involves a lot , At present, only the core , If there are other problems or Need all , Follow up github

Summary

The above is just an implementation method , You are welcome to recommend better ones to share

原网站

版权声明
本文为[Velly_ zheng]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/02/202202200529183876.html

随机推荐