Go框架三件套 | 青训营笔记

77 阅读7分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 5 天,本次是针对Gorm、Kitex、Hertz三件套的学习。

三件套:Gorm、Kitex、Hertz

Gorm是一个功能强大的ORM框架

Kitex是Golang微服务RPC框架

Hertz是HTTP框架

一、Gorm的基本使用 (gorm.cn/zh_CN/docs)

go get "gorm.io/driver/mysql"

go get "gorm.io/gorm"

package main
​
import (
   "gorm.io/driver/mysql"
   "gorm.io/gorm"
)
​
// 定义gorm model
type Product struct {
   Code  string
   Price uint
}
​
// 为model定义表名
func (p Product) Tablename() string {
   return "product"
}
​
func main() {
   //初始化数据库连接
   db, err := gorm.Open( //使用gorm.Open去传递一个mysql.Open,gorm根据不同的驱动支持不同的数据库
      mysql.Open("root:123456@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"),
      //通过&gorm.Config{}去传递一些自定义配置
      &gorm.Config{})
   if err != nil { //判断数据库是否连接成功
      panic("failed to connect database") //panic里面可以加一些错误信息
   }
   //支持创建一条和多条数据
   //创建一条数据时,传递的是一个对象
   //创建多条数据时,传递的是一个切片(数组)
   db.Create(&Product{Code: "D42", Price: 100})
   var product Product
   db.First(&product, 1)               //支持查一条数据(根据整形主键查找),传入的是product指针(gorm把查询到的字段反省回到指针,如果不是指针,写不回去)
   db.First(&product, "code=?", "D42") //后面是传递条件(查找code字段为D42的值)(First方法查询一条,Find方法可以查询多条)
   //更新数据(在Model上面已经定义了tableName),用 .Model去传递这个结构体;另外一种是使用 .Table,传递的是一个字符串
   db.Model(&product).Update("price", 200) //更新一列数据
   //更新多个字段
   db.Model(&product).Updates(Product{Price: 200, Code: "F42"}) //支持传递一个结构体,结构体本身有一个默认零值(gorm下使用结构体,仅更新非零值)
   //更新零值,传递一个map
   db.Model(&product).Updates(map[string]interface{}{"Price": 200, "Code": "F42"}) //支持传递一个map
   //删除(先一个结构体,再条件)
   db.Delete(product, 1)
​
}

Gorm官网:gorm.cn/zh_CN/docs/

Gorm的约定(默认)

  • gorm使用名为ID的字段作为主键,
  • 使用结构体的蛇形复数(生成的表是复数形式)作为表名,字段名的蛇形作为列名,
  • 使用CreateAt、UpdateAt字段作为创建、更新时间

支持的数据库:MySQL、SQLServer、PostgreSQL、SQLite

Gorm通过驱动连接数据库,如果需要连接其他类型的数据库,可以复用/自行开发驱动

四个数据库驱动程序,如果要连接到这些数据库,则需要导入不同的驱动程序包并定义不同的格式

MySQL

  • 导入:import " github.com/jinzhu/gorm/dialects/mysql" 或者导入" github.com/go-sql-driver/mysql"
  • DSN:"用户:密码@/dbname?charset = utf8 \ parseTime = True \ loc = Local"(用户是指用户名,密码是指密码,dbname是数据库名)

SQLServer

  • 导入:import _" github.com/jinzhu/gorm/dialects/postgres"
  • DSN:" sqlserver://用户名:密码@主机:端口?数据库= dbname"(用户名是指用户名,密码是指密码,主机是指主机地址,端口是指端口号,数据库是指数据库名称)

Sqlite3

导入:import _" github.com/jinzhu/gorm/dialects/sqlite"

DSN:连接到Sqlite3数据库的DSN只需要指定Sqlite3数据库文件的路径,例如:/tmp/gorm.db

PostgreSQL

导入:import _" github.com/jinzhu/gorm/dialects/mssql"

DSN:主机= myhost端口= myport用户= gorm dbname = gorm密码= mypassword(//host指主机地址,port指端口号,user指用户名,dbname指数据库名,password指密码)

type Good struct {
   ID    uint   `gorm:"primarykey"`   //指定主键
   Code  string `gorm:"column:code"`
   Price uint   `gorm:"column:price"`
}

使用clause.OnConflict处理数据冲突

//以不处理冲突为例,创建一条数据

p :=&Good{Code:"GSSS",ID:1}

db.Clauses(clause.OnConflict{DoNothing:true}).Create(&p) //调用Create、Delete、Update,这些都是finish的api,前面都是组合api,当调用这些动词api时(finish api),是真正地执行sql语句,如果.Create()后面再加上.Where()条件的话,是不生效的,因为调用到Create时就已经执行完了

使用default标签字段定义默认值

type User struct{
​
    ID int64
​
    Name string 'gorm:"default:galeone"'
​
    Age int64 '"gorm:default:18"'
​
}
​
​
查询数据:gorm.cn/zh_CN/docs/…

First:默认查一条数据,返回第一条查询到的数据,按照主键的升序,如果查询不到数据,就会返回ErrRecordNotFound

Find:查询多条数据,查询不到数据,返回一个空数组,不会返回err

结构体:当使用结构体作为条件查询时,gorm只会查询非零字段,即如果字段值为0,"",false或其他零值,该字段不会被用于构建查询条件,(更新字段类似)使用Map来构建查询条件(有零值时,也可以使用gorm提供的select的api(执行字段))

//select * from users where name=”xxx";

db.Where(&User{Name:"xxx",Age:0}).Find(&user) //传递结构体,查询时,因为结构体的零值问题,不会把零值的条件加进去

//select *from users where name="xxx" and age=0;

db.Where(map[string]interface{}{Name:"xxx",Age:0}).Find(&user) //传递map,会处理零值的问题

更新数据:gorm.cn/zh_CN/docs/…

更新单个列:

//update users set name="hello" where age>10;

db.Model(&User{ID:11}).Where("age>?",10).Update("name","hello") //使用Update时需要使用Model或者Table指定表名,否则报错

更新多个列(结构体+Updates):

//update users set name="hello",age=10,where id=11

db.Model(&User{ID:11}).Updates(User{Name:"hello",Age:10})

更新多个列(map+Updates):

//update users set name="hello",age=10,where id=11

db.Model(&User{ID:11}).Updates(map[string]interface{}{Name:"hello",Age:10})

更新选定字段

//update users set name="hello",where id=11

db.Model(&User{ID:11}).Select("name").Updates(map[string]interface{}{Name:"hello",Age:10})

SQL表达式更新

//update "users" set "age=age*2+100",where "id=1";

db.Model(&User{ID:1}).Update("age",gorm.Expr("age*?+?",2,100))

使用struct更新时,只会更新非零值,如果需要更新零值,可以使用Map更新或使用Select选择字段

删除数据: gorm.cn/zh_CN/docs/…

物理删除:(从数据库中真正删除)

db.Delete(&User{},10) //delete from users where id=10

db.Delete(&User{},"10") //delete from users where id=10 (默认识别id为主键)

db.Delete(&User{},[]int{1,2,3}) //delete from users where id in (1,2,3)

db.Where("name like ?","xx").Delete(User{}) //传入的是结构体,结构体已经实现了tablename,不需要调用.Model或者.tableName

db.Delete(User{},"name like ?","xx")

软删除:

gorm提供了gorm.DeleteAt实现软删

拥有软删能力的Model调用Delete时,记录不会从数据库中真正删除,但gorm会将DeleteAt置为当前时间,之后不能通过正常的查询方法找到该条记录,可以使用Unscoped查询到被软删的数据。

赋予软删功能,在结构体定义中加入:Deleted gorm.DeleteAt

事务:

Begin、Commit、Rollback

tx :=db.Begin() //开启事务,返回一个gorm对象,一定要返回这个对象,使用tx,而不是db,db.Begin()执行两个操作,一是固化一个连接,要保证使用事务的时使用的是同一个链接,golang底层对数据库操作使用的是连接池。

tx.Rollback() //回滚事务

tx.Commit() //提交事务

gorm提供Transaction方法用于自动提交事务,避免用户漏写Commit、Rollback

db, err := gorm.Open(
   mysql.Open("root:123456@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"),
   &gorm.Config{})
if err != nil {
   panic("failed to connect database")
}
if err :=db.Transaction(func(tx *gorm.DB) error{
    if err=tx.Create(&User{Name:"name"}).Error;err!=nil{
        return err
    }
    if err=tx.Create(&User{Name:"name1"}).Error;err!=nil{
        tx.Rollback()
        return err
    }
    return nil
});err!=nil{
    return
}
hook

使用hook时,会添加默认事务,如果任何hook返回错误,gorm将停止后续的操作并回滚事务

生态:
gorm代码生成工具github.com/go-gorm/gen
gorm分片库方案github.com/go-gorm/sha…
gorm手动索引github.com/go-gorm/hin…
gorm乐观锁github.com/go-gorm/opt…
gorm读写分离github.com/go-gorm/dbr…
gorm OpenTelemetry扩展github.com/go-gorm/ope…
二、Kitex(www.cloudwego.io/zh/docs/kit…

安装:

go install github.com/cloudwego/kitex/tool/cmd/kitex@latest

go install github.com/cloudwego/thriftgo@latest

kitex服务默认监听8888端口

IDL:

使用IDL定义服务与接口如果要进行RPC,需要知道对方接口、参数、返回值等,这就需要通过IDL来约定双方的协议。

生成代码:kitex -module example -service example echo.thrift

build.sh----构建脚本

kitex_gen-----IDL内容相关的生成代码,主要是基础的Server/Client代码

main.go-----程序入口

handler.go------用户在该文件里实现IDL Service定义的方法

三、Hertz(www.cloudwego.io/zh/docs/her…

Hertz提供了参数路由和通配路由,路由的优先级为:静态路由>命名路由>通配路由