Go使用XORM操作MySQL的陷阱盘点分析

 更新时间:2023年11月30日 11:26:58   作者:frank  
在 Go 语言开发中,大家为了方便,通常会选择使用 ORM 操作数据库,比如使用 XORM 或 GORM 操作 MySQL,本文我们来介绍一下使用 XORM[3] 操作 MySQL 可能会遇到的陷阱

使用 XORM 操作 MySQL 的陷阱

虽然使用 ORM 操作 MySQL 比直接使用标准库 `sql`[1] 和三方 MySQL 数据库驱动包[2]操作 MySQL 更加方便,但是也会遇到一些陷阱。

类型零值

在 Golang 中,每个数据类型都有各自的类型零值,比如 int 的零值是 0,string 的零值是 ''等。

示例代码:

package main
import (
 "fmt"
 _ "github.com/go-sql-driver/mysql"
 "xorm.io/xorm"
)
func main() {
 // 创建 Engine
 engine, err := xorm.NewEngine("mysql", "root:root@/example?charset=utf8")
 defer func() {
  err = engine.Close()
  if err != nil {
   fmt.Printf("engine close err=%v\n", err)
   return
  }
 }()
 if err != nil {
  fmt.Printf("init xorm engine fail, err=%v\n", err)
  return
 }
 // 更新数据
 example := &Example{
  Title: "go",
  View:  0,
 }
 condi := &Example{
  Id: 2,
 }
 affected, err := engine.Update(example, condi)
 if err != nil {
  fmt.Printf("Update err=%v\n", err)
  return
 }
 fmt.Printf("affected=%d\n", affected)
}
type Example struct {
 Id      int    `json:"id" form:"id"`
 Title   string `json:"title" form:"title"`
 View    int    `json:"view" form:"view"`
 Created int    `json:"created" form:"created" xorm:"created"`
 Updated int    `json:"updated" form:"updated" xorm:"updated"`
}

阅读上面这段代码,我们可以发现示例代码中将 id=2 的数据 view 字段更新为 0,因为 0 是 int 的类型零值,XORM 的 Update 方法会自动忽略类型零值,所以该数据 view 字段的值没有更改。

但是,在实际项目开发中,我们可能需要将某个字段的值更新为该字段类型的类型零值,此时我们该怎么操作呢?

affected, err := engine.Cols("title", "view").Update(example, condi)

我们可以使用 Cols() 方法,指定需要更新的字段,这样即便需要更新字段的值是该字段类型的类型零值,也可以正常更改。

提示:建议在设计数据库表时,字段的值尽量使用非类型零值。

自增 id

在插入数据时,我们可能需要返回自增 id,我们先看一段代码:

// 插入数据
example := &Example{
  Title: "PHP",
  View:  90,
}
affected, err := engine.Insert(example)
if err != nil {
  fmt.Printf("Insert err=%v\n", err)
  return
}
fmt.Printf("affected=%v\n", affected)

阅读上面这段代码,我们插入一条数据,返回结果是影响行数和错误信息,而不是直接返回该条数据的自增 id。

可能有些读者朋友们会接着使用查询方法,查询最新一条数据的 id,在并发请求数低的场景中,该方法是可以查到新插入数据的自增 id。

但是在并发请求数高的场景中,该方法查到的最新一条数据的 id,未必是我们刚插入的数据的自增 id。

id := example.Id
fmt.Printf("affected=%v || id=%d\n", affected, id)

阅读上面这段代码,我们想要获取新插入数据的自增 id,直接 example.Id 即可获取,但是前提条件是结构体中,id 字段使用 xorm:"autoincr" 标签。

更新 created 字段

我们在结构体中,使用标签 xorm:created 和 xorm:updated 即可自动插入当前时间。

但是,使用 xorm:created 标签的字段,只有在第一次插入数据时写入当前时间,此后将不再会更改;使用 xorm:updated 标签的字段,在第一次插入数据时写入当前时间,此后每次 Update 操作,时间都会更改。

如果我们的业务需求是需要更改使用 xorm:created 标签的字段,可以做到吗?

// 更改数据
example := &Example{
  Title: "JavaScript",
  View:  98,
}
condi := &Example{
  Id: 2,
}
affected, err := engine.Update(example, condi)
if err != nil {
  fmt.Printf("Update err=%v\n", err)
  return
}
fmt.Printf("affected=%d\n", affected)

阅读上面这段代码,我们发现执行 Update 方法之后,使用 xorm:updated 标签的字段的值被更改,而使用 xorm:created 标签的字段的值没被更改。

我们换一种更新数据的方式,代码如下:

// 更改数据
sql := "UPDATE example SET title=?, view=?, created=? WHERE id=?"
res, err := engine.Exec(sql, "Python", 60, time.Now().Unix(), 2)
if err != nil {
  fmt.Printf("Update err=%v\n", err)
  return
}
affected, err := res.RowsAffected()
if err != nil {
  fmt.Printf("RowsAffected err=%v\n", err)
  return
}
fmt.Printf("affected=%d\n", affected)

阅读上面这段代码,我们可以发现使用 Exec 方法执行原生 SQL 可以满足我们的需求。

总结

本文我们介绍了使用 XORM 操作 MySQL 时,新手读者朋友们可能会遇到的陷阱,希望可以给大家带来一些帮助,更多关于Go XORM操作MySQL的资料请关注脚本之家其它相关文章!

相关文章

  • golang 自旋锁的实现

    golang 自旋锁的实现

    这篇文章主要介绍了golang 自旋锁的实现,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-11-11
  • 详解golang中模板的常用语法

    详解golang中模板的常用语法

    这篇文章主要介绍了golang模板中的常用语法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-08-08
  • golang定时任务cron项目实操指南

    golang定时任务cron项目实操指南

    Go实现的cron 表达式的基本语法跟linux 中的 crontab基本是类似的,下面这篇文章主要给大家介绍了关于golang定时任务cron项目实操的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2022-12-12
  • Golang Defer作用域及执行顺序使用案例

    Golang Defer作用域及执行顺序使用案例

    这篇文章主要为大家介绍了Golang Defer作用域及执行顺序使用案例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-12-12
  • Go语言LeetCode题解682棒球比赛

    Go语言LeetCode题解682棒球比赛

    这篇文章主要为大家介绍了Go语言LeetCode题解682棒球比赛示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • Go依赖注入DI工具wire使用详解(golang常用库包)

    Go依赖注入DI工具wire使用详解(golang常用库包)

    依赖注入是指程序运行过程中,如果需要调用另一个对象协助时,无须在代码中创建被调用者,而是依赖于外部的注入,本文结合示例代码给大家介绍Go依赖注入DI工具wire使用,感兴趣的朋友一起看看吧
    2022-04-04
  • 在ubuntu下安装go开发环境的全过程

    在ubuntu下安装go开发环境的全过程

    Go语言是谷歌公司开发的编程语言,虽然安装和配置go很简单,但是很多初学者在第一次安装go环境时会遇到各种坑,下面这篇文章主要给大家介绍了关于在ubuntu下安装go开发环境的相关资料,文中通过图文介绍的非常详细,需要的朋友可以参考下
    2022-08-08
  • Golang中的http.Server源码深入分析

    Golang中的http.Server源码深入分析

    这篇文章主要介绍了Golang中的http.Server源码,实现一个http.Server非常容易,只需要短短几行代码,同时有了协程的加持,Go实现的http.Server能够取得非常优秀的性能,下面我们来分析看看http.Server的源码
    2023-05-05
  • Mac GoLand打不开(闪退)也不报错的解决方案

    Mac GoLand打不开(闪退)也不报错的解决方案

    这篇文章主要介绍了Mac GoLand打不开(闪退)也不报错的解决方案,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-04-04
  • 详解Golang time包中的结构体time.Ticker

    详解Golang time包中的结构体time.Ticker

    在日常开发过程中,会频繁遇到对时间进行操作的场景,使用 Golang 中的 time 包可以很方便地实现对时间的相关操作,接下来的几篇文章会详细讲解 time 包,本文讲解一下 time 包中的结构体 time.Ticker,需要的朋友可以参考下
    2023-08-08

最新评论