作者:可乐可乐可:https://blog.csdn.net/weixin_44494373
上一篇:Go Web开发入门指南<前半>
内容:Go Web开发套装,Gin,Gorm,viper,validator,zap,go-redis,grpc本文难度:适合入门
上半部分,我们讲了讲Gin,想做到web开发,我们现在已经有了基础的MVC,我们只需要ORM框架(操作数据库)日志框架就能满足基本80%的需求了,初次之外,就是配置文件的支持,rpc微服务体系支持
我们一点一点来扩展我们的知识范围,相比各位已经很心急了,那我们按照这样的流程进行讲解
ORM框架gorm -> 日志框架:logrus、zap -> 配置文件viper
功夫再深,也逃不了CRUD的命运,我与大佬的不同,不在与拧螺丝的工作,在于在什么地点拧螺丝,(开玩笑)
Go是编程语言里面的新生儿这种事情就不用再强调了,新时代的CRUD,呸呸呸,ORM操作,加上Go简洁的追求,Go的ORM框架用起来很轻松(但是经验告诉我,用起来越简单,听起来越全自动的东西,都越恐怖,声明,本句与Kubernetes没有任何关系)
这里也算提个醒吧,工具自动化是好事,但是这意味着你可能会有需要进入这自动化的代码中,看看他的原理,找到你的解答
来,先码一下gorm的官方文档:文档地址
官方文档写的很棒,多看看官方文档(毕竟中文版本)
写到这里,弟弟又去复习了一遍文档,gorm的文档,确实。。太到位了,建议各位看看官方文档吧,这里我给大家讲一下基本的思路让大家对gorm里的一些概念有个基础的认识
但是不写Gorm,总感觉很空虚,思来想去,最后还是写了出来,我会尽量用简单便于理解的方式帮助大家了解gorm,后面就只需要在官方文档找api了
操作数据库,一般需要两个部分,1、数据库驱动 2、orm框架
而一个orm框架,大致会有这些构建
这几个步骤也是我们使用一个ORM框架的基本步骤
gorm没有另辟蹊径,是很经典的类型->表,字段对应表字段
我们创建一个model
package model
// data将会变成表名称
type Data struct {
ID uint `json:"id,omitempty" gorm:"primaryKey"`
Msg string `json:"msg,omitempty" gorm:"type:varchar(10) unique"`
}
关于表名与字段这里需要注意以下
ID
作为主键默认情况下,GORM 会使用 ID
作为表的主键。
type User struct {
ID string // 默认情况下,名为 `ID` 的字段会作为表的主键
Name string
}
你可以通过标签 primaryKey
将其它字段设为主键
// 将 `UUID` 设为主键
type Animal struct {
ID int64
UUID string `gorm:"primaryKey"`
Name string
Age int64
}
此外,您还可以看看 复合主键
GORM 使用结构体名的 蛇形命名
作为表名。对于结构体 User
,根据约定,其表名为 users
这里我很疑惑,我们使用AaBc会被创建为aa_bcs,但是我们命名为Data,将创建为data
总之,官方并没有仔细的叙述这里的逻辑,很无奈,我们只能被逼再次打开源码(好耶!
进入(db *DB) AutoMigrate(dst …interface{})方法,
我们发现他是适配器模式
,调用了db.Migrator().AutoMigrate(dst…)
进入db.Migrator().AutoMigrate(dst…),这个接口只有一个实现类,妥妥的适配器模式
在这里,我们大致看了看,逻辑分为创建和修改表,不用多想,他们的策略一定是一样的,我们看create即可
代码贴在了下面,大家来一起观赏一下,gorm的骚操作,原来也就是sql的拼接罢了
各位先复习一下sql创建表的语句
CREATE TABLE Persons
(
PersonID int,
LastName varchar(255),
FirstName varchar(255),
Address varchar(255),
City varchar(255)
);
大概看看就行,流程其实很简单,就是拼凑出一个sql
func (m Migrator) CreateTable(values ...interface{
}) error {
// 传进来的是多个表,遍历创建每一个
for _, value := range m.ReorderModels(values, false) {
// 开一个session
tx := m.DB.Session(&gorm.Session{
})
// 开始拼接sql
if err := m.RunWithValue(value, func(stmt *gorm.Statement) (errr error) {
// CREATE TABLE ? (
var (
// sql语句,参数用?
createTableSQL = "CREATE TABLE ? ("
// sql参数
values = []interface{
}{
m.CurrentTable(stmt)}
hasPrimaryKeyInDataType bool
)
// 拼接上每一个字段,还会加上PRIMARY KEY
// CREATE TABLE ? ( ? ? )
for _, dbName := range stmt.Schema.DBNames {
field := stmt.Schema.FieldsByDBName[dbName]
createTableSQL += "? ?"
// 获取标签,取出字符串 PRIMARY KEY
hasPrimaryKeyInDataType = hasPrimaryKeyInDataType || strings.Contains(strings.ToUpper(string(field.DataType)), "PRIMARY KEY")
values = append(values, clause.Column{
Name: dbName}, m.DB.Migrator().FullDataTypeOf(field))
createTableSQL += ","
}
if !hasPrimaryKeyInDataType && len(stmt.Schema.PrimaryFields) > 0 {
createTableSQL += "PRIMARY KEY ?,"
primaryKeys := []interface{
}{
}
for _, field := range stmt.Schema.PrimaryFields {
primaryKeys = append(primaryKeys, clause.Column{
Name: field.DBName})
}
values