当前位置:网站首页>Go service platform project (I) design of database tables and use of gendry Library
Go service platform project (I) design of database tables and use of gendry Library
2022-06-21 22:42:00 【Love letters are not included】
One 、 Database table design
In the course of the project, try to use mysql Command line to operate , But to improve efficiency , Visual tools can be used when creating tables and changing field information , Check the data and fields with the command line . 
There are eight data sheets for the whole project ,user Table and advisor The table records users' and consultants' information model Field data ,orders surface 、service Table and review Table records orders separately 、 Service and order review data of three entities ,adv_coin Table and user_coin The table is used to record the gold coin running records of users and consultants . The following are a few things to pay attention to in database design :
1. Primary key Id The design of the
In terms of database theory , Each entity should be designed with a primary key Id Field , A record that uniquely identifies the entity . For example, user table settings uid, Consultant table settings aid, Service table settings sid.
about id Field , In general, it will increase by itself , And the starting point of self increment will be set . In order to distinguish the records of each entity , Usually set different self increasing starting points with strong differentiation . For example, in this project , I give uid Set the starting point of self increment to 60000,aid by 80000,sid by 50000. For projects with huge data systems , Consider multiple digit numbers id Set up .
2. The name of the field
The database fields are named with underscores , If the field is strongly related to the entity , You don't have to add an identifier in front of it . such as user The name field of the user in the table , Do not name it user_name, Direct use name that will do . However, if the field has no attribute relationship with the entity , An identifier must be added to the front , for example orders User name in the table , use user_name It would be more appropriate .
3. Non empty setting of field
In general, try to ensure that the fields in the table are not empty , Unless the data of this field can be ignored or only added in subsequent data operations .
For example, in the order table answer Field , Because there is no answer to the question when creating the order , Only when the corresponding consultant answers the order will there be an answer , Therefore, this field cannot be set to non empty . Except in similar cases , All other fields are set to non empty .
4. Special field handling
Projects often encounter some enumerations or fields with format requirements . For example, the gender field is in model Set up in Int enumeration , So the type in the table is set to Int. For example, the average score field of the consultant shall be one decimal place and the maximum is 10, Type is available decimal(2,1).(decimal(x,y),x Represents the total number of digits ,y Identify the number of digits after the decimal point )
Two 、 Configure the database in the project
After designing the database , The next step is to configure the database in the project . In general, the configuration information of the database ( Port number 、 user name 、 password ) Write in the configuration file or constant file , However, due to the small volume of the project , I wrote it directly in the database initialization function .
First , We need to create a separate folder in the project to place the database configuration files , I'm going to call it common, Then create db.go file , Write the functions of database initialization and obtaining database pointer in it .
db.go :GO-GIN / common / db.go
package common
import (...)
var DB *sql.DB
func InitDB() *sql.DB {
scanner.SetTagName("key")
// here root:password The user name of your database : password , demo Is the name of the connected database , 3306 Is the port number ( Default )
db, err := sql.Open("mysql", "root:[email protected](127.0.0.1:3306)/demo?charset=utf8")
if err != nil {
fmt.Println(err)
} else {
fmt.Println(" Database connection successful !")
}
DB = db
return db
}
func GetDB() *sql.DB {
return DB
}
After configuration , stay main.go Add... To the file :
main.go :GO-GIN / main.go
func main() {
r := gin.Default()
// Initialize database
common.InitDB()
// establish DB example
db := common.GetDB()
// Delay database shutdown
defer db.Close()
// Initialize route
r = router.InitRouter(r)
r.Run(":8000")
}
In this way, the basic configuration of the database is completed .
3、 ... and 、gendry Use
Gendry Is a database for auxiliary operation Go package . be based on go-sql-driver/mysql, It provides a series of methods to call the standard library for you database/sql Methods in prepare parameters .( Official link jump )
Gendery It is mainly divided into 3 A separate part :
1.manager:
It is mainly used to initialize the connection pool ( That is to say sql.DB object ), Set various parameters , So it's called manager. You can set any go-sql-driver/mysql Parameters supported by the driver .
2.builder:
builder seeing the name of a thing one thinks of its function , Is to build and generate sql sentence . Handwriting sql Although intuitive and simple , But the maintainability is poor , The main thing is that hard coding is error prone .builder Is not a ORM, It just provides a simple API Help you generate sql sentence .
3.scanner:
After performing the database operation , To put The returned result set and the custom struct mapping .Scanner Provide a simple interface to bind result set and custom type through reflection .scanner The reflection will use the structure of tag, Default tagName yes ddb:“xxx”, You can also customize it .
The... Set in this project scannar mapping tag by “key”, stay InitDB() Function :
scanner.SetTagName("key")
For a field , Set up key Is the field name in the corresponding data table .scanner The function maps to struct On .
Four 、 Function encapsulation and use
Function encapsulation is stored in a separate folder , This project is named utils. establish gen.go file , preservation gendry Encapsulation of statements .
gen.go :GO-GIN / utils / gen.go
1. Lookup function - Universal - Binding structure
import (
"database/sql"
"strconv"
...
qb "github.com/didi/gendry/builder"
"github.com/didi/gendry/scanner"
_ "github.com/go-sql-driver/mysql"
"go.uber.org/zap"
)
func GenSelectOne(obj interface{
}, table string, where map[string]interface{
}, selectField []string) error {
var db = common.GetDB()
cond, vals, _ := qb.BuildSelect(table, where, selectField)
rows, err := db.Query(cond, vals...)
if err != nil {
common.Log.Info(config.ErrSelect.Msg, zap.Error(err))
return err
}
defer rows.Close()
if err := scanner.Scan(rows, obj); err != nil {
common.Log.Info(config.ErrScan.Msg, zap.Error(err))
return err
}
return err
}
First, get the database object , And then use gendry-builder Of BuildSelect Function to build a query statement cond And query parameters vals, And then use mysql Native query statements for db.Query The query , Get the results rows.( Be careful : Yes rows Close the after operation rows, See the official website for specific reasons ). Last use gendry-scannar Medium Scan function , Bind the result to the incoming structure obj in .
2. Update function - Universal - Binding structure
func GenUpdateNew(obj interface{
}, table string, where map[string]interface{
}) error {
var db = common.GetDB()
update := map[string]interface{
}{
}
// Will the incoming struct turn map, Used to update the
MapByReflect(update, obj)
cond, vals, _ := qb.BuildUpdate(table, where, update)
_, err := db.Exec(cond, vals...)
if err != nil {
common.Log.Info(config.ErrUpdate.Msg, zap.Error(err))
}
return err
}
In the update function, the struct Convert to a map, Then put it into the update statement to complete the update . The conversion function will be explained in detail in subsequent articles .
3. Insert the function - Universal - Binding structure
// Insert
func GenInsertNew(obj interface{
}, table string) error {
var db = common.GetDB()
data := map[string]interface{
}{
}
var insertData []map[string]interface{
}
MapByReflect(data, obj)
insertData = append(insertData, data)
cond, vals, _ := qb.BuildInsert(table, insertData)
_, err := db.Exec(cond, vals...)
if err != nil {
common.Log.Info(config.ErrInsert.Msg, zap.Error(err))
}
return err
}
4. Lookup function - customized - Bind structure list
// multi-select - List of consultants
func GenSelectAdvisor(objArray *[]model.Advisor, table string, where map[string]interface{
}, selectField []string) error {
var db = common.GetDB()
cond, vals, _ := qb.BuildSelect(table, where, selectField)
rows, err := db.Query(cond, vals...)
if err != nil {
common.Log.Info(config.ErrSelect.Msg, zap.Error(err))
return err
}
defer rows.Close()
if err := scanner.Scan(rows, objArray); err != nil {
common.Log.Info(config.ErrScan.Msg, zap.Error(err))
return err
}
return err
}
When we need to query multiple entities , Just pass in a struct Array . But after many attempts , It is found that the input parameters cannot be uniformly defined as []interface, Only input function can be customized . The above query function is a customized query consultant list function , Pass in a consultant structure array and bind . Other similar functions only need to modify the structure type of the input parameter .
5. Use of functions
user.go :GO-GIN / service / user.go
import (
"xxx/go-gin/common"
"xxx/go-gin/config"
"xxx/go-gin/model"
"xxx/go-gin/utils"
"go.uber.org/zap"
)
// The user gets the list of consultants
func GetAdvisorList(advisorList *[]model.Advisor) error {
where := map[string]interface{
}{
}
if err := utils.GenSelectAdvisor(advisorList, "advisor", where, config.AdvSelectAll); err != nil {
common.Log.Info(config.ErrSelect.Msg, zap.Error(err))
return err
}
return nil
}
The statement of database operation is used in Service layer , Only return one error. stay Service The layer only needs to error Print log , Then return to Controller Just layer . The specific logic will be discussed in detail in subsequent articles .
5、 ... and 、 Summary and reflection
The design of database and the writing and encapsulation of operation statements are the basis of the whole project , Many details need attention , Otherwise, I will come back later to rework and modify , Efficiency will be greatly reduced .
meanwhile , Data flow should preferably depend on struct Structure , Match the operation data with the corresponding struct Binding , Then carry out data transmission and next step processing , This comparison map Moving around is much more efficient .
边栏推荐
- Fedora 36 compiling and installing opencv 4.6.0 -- the road to building a dream
- 将字符串按长度截取成数组
- Uwp shadow effect
- The method of ram and ROM initialization in FPGA design
- Left hand code, right hand open source, part of the open source road
- Niuke month race - insectivores on the ring
- 力扣刷題集結4(mysql版本)
- 左手代码,右手开源,开源路上的一份子
- Migration of stm32f407 program to stm32f429
- Pycharm下可以正常运行,Pyinstaller打包软件报出Fatal error
猜你喜欢
随机推荐
LeetCode-543-二叉树的直径
High level project - project initiation management
KVM virtual machine rescue mode modifying root password -- the road to building a dream
Pychart can run normally, and pyinstaller package software reports fatal error
Uwp confirms whether there is pop-up display
Qt滚动区域QScrollArea
Niuke month race - insectivores on the ring
GDB debugging practice (10) multi thread debugging
Pycharm使用指南
专业字体设计编辑Glyphs 3
C# 删除正在使用的文件
Implement a middleware from -1
fork-join线程池
WPF dependent properties
将字符串按长度截取成数组
力扣:零钱兑换
Uwp dispatcher usage
vb屏幕分辨率设置和获取_hawkol_新浪博客
WPF tablet
[in depth understanding of tcapulusdb technology] how to realize single machine installation of tmonitor







