Go 语言使用 XORM 操作 MySQL 的陷阱

2023-10-27 05:01

本文主要是介绍Go 语言使用 XORM 操作 MySQL 的陷阱,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

介绍

在 Go 语言开发中,大家为了方便,通常会选择使用 ORM 操作数据库,比如使用 XORM 或 GORM 操作 MySQL。

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

本文我们来介绍一下使用 XORM 操作 MySQL 可能会遇到的陷阱。


使用 XORM 操作 MySQL 的陷阱

类型零值

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

示例代码:

package mainimport ("fmt"_ "github.com/go-sql-driver/mysql""xorm.io/xorm"
)func main() {// 创建 Engineengine, 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 可以满足我们的需求。


 3 

总结

本文我们主要介绍为什么 Go 协程比进程和线程占用的系统资源低,通过进程、线程、协程的 CPU 资源和内存占用的比较,发现无论是在切换时消耗的 CPU 资源(时间片),还是内存占用,Go 协程都有明显优势。

一句话总结就是 Go 协程的切换成本和内存占用比线程和进程都低。

需要注意的是,Go 协程占用系统资源低,并不代表可以无限创建 Go 协程。

这篇关于Go 语言使用 XORM 操作 MySQL 的陷阱的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/285942

相关文章

Go之errors.New和fmt.Errorf 的区别小结

《Go之errors.New和fmt.Errorf的区别小结》本文主要介绍了Go之errors.New和fmt.Errorf的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考... 目录error的基本用法1. 获取错误信息2. 在条件判断中使用基本区别1.函数签名2.使用场景详细对

Mac电脑如何通过 IntelliJ IDEA 远程连接 MySQL

《Mac电脑如何通过IntelliJIDEA远程连接MySQL》本文详解Mac通过IntelliJIDEA远程连接MySQL的步骤,本文通过图文并茂的形式给大家介绍的非常详细,感兴趣的朋友跟... 目录MAC电脑通过 IntelliJ IDEA 远程连接 mysql 的详细教程一、前缀条件确认二、打开 ID

Nginx中配置使用非默认80端口进行服务的完整指南

《Nginx中配置使用非默认80端口进行服务的完整指南》在实际生产环境中,我们经常需要将Nginx配置在其他端口上运行,本文将详细介绍如何在Nginx中配置使用非默认端口进行服务,希望对大家有所帮助... 目录一、为什么需要使用非默认端口二、配置Nginx使用非默认端口的基本方法2.1 修改listen指令

Python WebSockets 库从基础到实战使用举例

《PythonWebSockets库从基础到实战使用举例》WebSocket是一种全双工、持久化的网络通信协议,适用于需要低延迟的应用,如实时聊天、股票行情推送、在线协作、多人游戏等,本文给大家介... 目录1. 引言2. 为什么使用 WebSocket?3. 安装 WebSockets 库4. 使用 We

python中的显式声明类型参数使用方式

《python中的显式声明类型参数使用方式》文章探讨了Python3.10+版本中类型注解的使用,指出FastAPI官方示例强调显式声明参数类型,通过|操作符替代Union/Optional,可提升代... 目录背景python函数显式声明的类型汇总基本类型集合类型Optional and Union(py

MySQL的配置文件详解及实例代码

《MySQL的配置文件详解及实例代码》MySQL的配置文件是服务器运行的重要组成部分,用于设置服务器操作的各种参数,下面:本文主要介绍MySQL配置文件的相关资料,文中通过代码介绍的非常详细,需要... 目录前言一、配置文件结构1.[mysqld]2.[client]3.[mysql]4.[mysqldum

MySQL中查询和展示LONGBLOB类型数据的技巧总结

《MySQL中查询和展示LONGBLOB类型数据的技巧总结》在MySQL中LONGBLOB是一种二进制大对象(BLOB)数据类型,用于存储大量的二进制数据,:本文主要介绍MySQL中查询和展示LO... 目录前言1. 查询 LONGBLOB 数据的大小2. 查询并展示 LONGBLOB 数据2.1 转换为十

Java使用正则提取字符串中的内容的详细步骤

《Java使用正则提取字符串中的内容的详细步骤》:本文主要介绍Java中使用正则表达式提取字符串内容的方法,通过Pattern和Matcher类实现,涵盖编译正则、查找匹配、分组捕获、数字与邮箱提... 目录1. 基础流程2. 关键方法说明3. 常见场景示例场景1:提取所有数字场景2:提取邮箱地址4. 高级

使用SpringBoot+InfluxDB实现高效数据存储与查询

《使用SpringBoot+InfluxDB实现高效数据存储与查询》InfluxDB是一个开源的时间序列数据库,特别适合处理带有时间戳的监控数据、指标数据等,下面详细介绍如何在SpringBoot项目... 目录1、项目介绍2、 InfluxDB 介绍3、Spring Boot 配置 InfluxDB4、I

使用Java读取本地文件并转换为MultipartFile对象的方法

《使用Java读取本地文件并转换为MultipartFile对象的方法》在许多JavaWeb应用中,我们经常会遇到将本地文件上传至服务器或其他系统的需求,在这种场景下,MultipartFile对象非... 目录1. 基本需求2. 自定义 MultipartFile 类3. 实现代码4. 代码解析5. 自定