【Go电商实战04】为什么GoFrame不支持migrate功能?我还特意去问了框架作者

简介: 这期内容带大家完成轮播图的修改功能

本期概要

这期内容带大家完成轮播图的修改功能,继续结合实战,带大家学会:

  1. 初学者必知必会:Go中没有null、none,只有nil
  2. 【有问必答系列】为什么GoFrame不支持migrate功能? 为了回答读者的问题我还特意问了框架作者。
  3. ORM链式操作-字段过滤的知识点


初学者必须搞懂:

  1. 在 Go 中,没有null、none、NULL、None
  2. 任何类型在未初始化时都对应一个零值:布尔类型是 false ,整型是 0 ,字符串是 ""
  3. 而指针,函数,interface,slice,channel和map的零值都是 nil

为什么GoFrame不支持migrate功能?

下图是星友问我的问题,我翻遍了文档也没找到相关的资料,猜测应该是不支持的。

image.png

于是问了goframe作者,被明确告知:goframe不支持,并且以后也不会支持。

作者也详细解答了不支持的原因,goframe作者团队的考虑是这样的:

a59fcb82d215e1b652d20c82ea7ff27.png

因为我做的项目比较多,在数据库表结构管理方面踩过坑。还是比较能接受goframe作者观点的。

migrate这种功能确实能方便开发者,但是在企业级项目中,尤其是TOB的业务,稳定是第一要务。migrate功能虽然方便,但是不够严谨,如果没有很强的规范去约束团队成员的使用,很容易出问题,出了问题就不是小问题,所以不敢用。

这也让我想起了另外一件事情:

前段时间在review代码时,发现了一个“无条件”的删除脚本在运行,心头一惊啊!这要是把数据删了可麻烦了。但是查询DB发现没有删除数据。

我详细查了官方文档,没有被删数据的原因是这样的:

goframe是一款用于企业生产级别的框架,各个模块设计严谨,工程实践的细节处理得比较好。为安全性保证、防止误操作,Update及Delete方法必须带有Where条件才能提交执行,否则将会错误返回,错误信息如:there should be WHERE condition statement for XXX operation。

好吧,感谢,真是救我狗命了,哈哈。

也正是因为自己做了很多项目,踩了很多坑,碰到了不少这种细节问题。

目前才有了“从追求开发效率”到“追求项目稳定性”的转变。

在这里也回答一下最近大家私信我的问题吧:“为什么我使用goframe框架做这个电商实战项目?”

原因很简单,我结合自己的经历,觉得GoFrame是一个适合企业级项目比较严谨的框架,能少踩坑,避免一些麻烦。虽然入门门槛是有的,但是在“工程化开发设计”的规范下,后续的维护成本还是比较低的。所以才带大家使用这个框架做电商项目的。

好了,不同的场景,不同的项目有不同的解决方案,不同的优选框架。这个问题没有标准答案,结合自己的需求去选择合适的解决方案吧。

欢迎大家找我交流,多提像这位读者一样有价值的问题,一起进步!

Fields/FieldsEx字段过滤

  1. Fields  用于指定需要操作的表字段,包括查询字段、写入字段、更新字段等过滤;
  2. FieldsEx  用于例外的字段指定,可用于查询字段、写入字段、更新字段等过滤;

Fields示例

  1. 假如user表有4个字段uid,  nickname,  passport,  password
  2. 查询字段过滤
 // SELECT `uid`,`nickname` FROM `user` ORDER BY `uid` asc
 g.Model("user").Fields("uid, nickname").Order("uid asc").All()

3.写入字段过滤

m := g.Map{
     "uid"      : 10000,
     "nickname" : "王中阳 Go",
     "passport" : "wangzhongyang",
     "password" : "123456",
 }
 g.Model(table).Fields("nickname,passport,password").Data(m).Insert()
 // INSERT INTO `user`(`nickname`,`passport`,`password`) VALUES('王中阳 Go','wangzhongyang','123456')

FieldsEx示例

  1. 假如user表有4个字段uid,  nickname,  passport,  password
  2. 查询字段排除
 // SELECT `uid`,`nickname` FROM `user`
 g.Model("user").FieldsEx("passport, password").All()

3.写入字段排除

 m := g.Map{
     "uid"      : 10000,
     "nickname" : "王中阳 Go",
     "passport" : "wangzhongyang",
     "password" : "123456",
 }
 g.Model(table).FieldsEx("uid").Data(m).Insert()
 // INSERT INTO `user`(`nickname`,`passport`,`password`) VALUES('王中阳 Go','wangzhongyang','123456')

OmitEmpty空值过滤

当  map/struct  中存在空值如  nil,"",0  时,默认情况下,gdb将会将其当做正常的输入参数,因此这些参数也会被更新到数据表。OmitEmpty特性可以在将数据写入到数据库之前过滤空值数据的字段。

相关方法:

func (m *Model) OmitEmpty() *Model
func (m *Model) OmitEmptyWhere() *Model
func (m *Model) OmitEmptyData() *Model 

OmitEmpty方法会同时过滤WhereData中的空值数据,而通过OmitEmptyWhere/OmitEmptyData方法可以执行特定的字段过滤。

写入/更新操作

空值会影响于写入/更新操作方法,如Insert,  Replace,  Update,  Save操作。如以下操作(以map为例,struct同理):

// UPDATE `user` SET `name`='wangzhongyang',update_time=null WHERE `id`=1
g.Model("user").Data(g.Map{
    "name"        : "wangzhongyang",
    "update_time" : nil,
}).Where("id", 1).Update()

针对空值情况,我们可以通过OmitEmpty方法来过滤掉这些空值。例如,以上示例可以修改为:

// UPDATE `user` SET `name`='wangzhongyang' WHERE `id`=1
g.Model("user").OmitEmpty().Data(g.Map{
    "name"        : "wangzhongyang",
    "update_time" : nil,
}).Where("id", 1).Update()

对于struct数据参数,我们也可以进行空值过滤。操作示例:

type User struct {
    Id         int    `orm:"id"`
    Passport   string `orm:"passport"`
    Password   string `orm:"password"`
    NickName   string `orm:"nickname"`
    CreateTime string `orm:"create_time"`
    UpdateTime string `orm:"update_time"`
}
user := User{
    Id        : 1,
    NickName  : "wangzhongyang",
    UpdateTime: gtime.Now().String(),
}
g.Model("user").OmitEmpty().Data(user).Insert()
// INSERT INTO `user`(`id`,`nickname`,`update_time`) VALUES(1,'wangzhongyang','2019-10-01 12:00:00')

注意:批量写入/更新操作中OmitEmpty方法将会失效,因为在批量操作中,必须保证每个写入记录的字段是统一的。

延伸知识点:

关于omitempty标签与OmitEmpty方法:

1.针对于struct的空值过滤大家会想到omitempty的标签。该标签常用于json转换的空值过滤,也在某一些第三方的ORM库中用作struct到数据表字段的空值过滤,即当属性为空值时不做转换。

2.omitempty标签与OmitEmpty方法所达到的效果是一样的。在ORM操作中,我们不建议对struct使用omitempty的标签来控制字段的空值过滤,而建议使用OmitEmpty方法来做控制。因为该标签一旦加上之后便绑定到了struct上,没有办法做灵活控制;而通过OmitEmpty方法使得开发者可以选择性地、根据业务场景对struct做空值过滤,操作更加灵活。

数据查询操作

空值也会影响数据查询操作,主要是影响where条件参数。我们可以通过OmitEmpty方法过滤条件参数中的空值。

使用示例:

// SELECT * FROM `user` WHERE `passport`='wangzhongyang' LIMIT 1
r, err := g.Model("user").Where(g.Map{
    "nickname" : "",
    "passport" : "wangzhongyang",
}).OmitEmpty().One()
type User struct {
    Id         int    `orm:"id"`
    Passport   string `orm:"passport"`
    Password   string `orm:"password"`
    NickName   string `orm:"nickname"`
    CreateTime string `orm:"create_time"`
    UpdateTime string `orm:"update_time"`
}
user := User{
    Passport : "wangzhongyang",
}
r, err := g.Model("user").OmitEmpty().Where(user).One()
// SELECT * FROM `user` WHERE `passport`='wangzhongyang' LIMIT 1

OmitNil空值过滤

当  map/struct  中存在空值如  nil时,默认情况下,gdb将会将其当做正常的输入参数,因此这些参数也会被更新到数据表。OmitNil特性可以在将数据写入到数据库之前过滤空值数据的字段。与OmitEmpty特性的区别在于,OmitNil只会过滤值为nil的空值字段,其他空值如"",0并不会被过滤。

相关方法:

func (m *Model) OmitNil() *Model
func (m *Model) OmitNilWhere() *Model
func (m *Model) OmitNilData() *Model 

OmitNil方法会同时过滤WhereData中的空值数据,而通过OmitNilWhere/OmitNilData方法可以执行特定的字段过滤。

初学Go必看

出过你有一定的GO基础,相信看完文章之后就懂了,因为并不是很进阶的知识点。

如果你是初学Go的小白,建议你观看我在B站录制的免费视频: 【电商实战04】ORM链式操作之字段过滤&粉丝有问必答 ,让你少踩坑,高效学。


公众号:程序员升职加薪之旅

微信号:wangzhongyang1993

B站视频:王中阳Go


相关文章
|
2月前
|
Shell Go API
Go语言grequests库并发请求的实战案例
Go语言grequests库并发请求的实战案例
|
2月前
|
JSON Go API
使用Go语言和Gin框架构建RESTful API:GET与POST请求示例
使用Go语言和Gin框架构建RESTful API:GET与POST请求示例
|
2月前
|
安全 大数据 Go
深入探索Go语言并发编程:Goroutines与Channels的实战应用
在当今高性能、高并发的应用需求下,Go语言以其独特的并发模型——Goroutines和Channels,成为了众多开发者眼中的璀璨明星。本文不仅阐述了Goroutines作为轻量级线程的优势,还深入剖析了Channels作为Goroutines间通信的桥梁,如何优雅地解决并发编程中的复杂问题。通过实战案例,我们将展示如何利用这些特性构建高效、可扩展的并发系统,同时探讨并发编程中常见的陷阱与最佳实践,为读者打开Go语言并发编程的广阔视野。
|
3月前
|
消息中间件 缓存 Kafka
go-zero微服务实战系列(八、如何处理每秒上万次的下单请求)
go-zero微服务实战系列(八、如何处理每秒上万次的下单请求)
|
3月前
|
缓存 NoSQL Redis
go-zero微服务实战系列(七、请求量这么高该如何优化)
go-zero微服务实战系列(七、请求量这么高该如何优化)
|
2月前
|
消息中间件 NoSQL Go
PHP转Go系列 | ThinkPHP与Gin框架之Redis延时消息队列技术实践
【9月更文挑战第7天】在从 PHP 的 ThinkPHP 框架迁移到 Go 的 Gin 框架时,涉及 Redis 延时消息队列的技术实践主要包括:理解延时消息队列概念,其能在特定时间处理消息,适用于定时任务等场景;在 ThinkPHP 中使用 Redis 实现延时队列;在 Gin 中结合 Go 的 Redis 客户端库实现类似功能;Go 具有更高性能和简洁性,适合处理大量消息。迁移过程中需考虑业务需求及系统稳定性。
|
3月前
|
消息中间件 SQL 关系型数据库
go-zero微服务实战系列(十、分布式事务如何实现)
go-zero微服务实战系列(十、分布式事务如何实现)
|
3月前
|
消息中间件 NoSQL Kafka
go-zero微服务实战系列(九、极致优化秒杀性能)
go-zero微服务实战系列(九、极致优化秒杀性能)
|
8天前
|
存储 JSON 监控
Viper,一个Go语言配置管理神器!
Viper 是一个功能强大的 Go 语言配置管理库,支持从多种来源读取配置,包括文件、环境变量、远程配置中心等。本文详细介绍了 Viper 的核心特性和使用方法,包括从本地 YAML 文件和 Consul 远程配置中心读取配置的示例。Viper 的多来源配置、动态配置和轻松集成特性使其成为管理复杂应用配置的理想选择。
27 2
|
6天前
|
Go 索引
go语言中的循环语句
【11月更文挑战第4天】
15 2