GO学习之 数据库(mysql)

GO系列

1、GO学习之Hello World
2、GO学习之入门语法
3、GO学习之切片操作
4、GO学习之 Map 操作
5、GO学习之 结构体 操作
6、GO学习之 通道(Channel)
7、GO学习之 多线程(goroutine)
8、GO学习之 函数(Function)
9、GO学习之 接口(Interface)
10、GO学习之 网络通信(Net/Http)
11、GO学习之 微框架(Gin)
12、GO学习之 数据库(mysql)

文章目录

  • GO系列
  • 前言
  • 一、简介
  • 二、准备操作
  • 三、Insert 操作
  • 四、Delete 操作
  • 五、Update 操作
    • 5.1 获取数据库链接
    • 5.2 更新操作
  • 六、Select 操作
  • 五、事务
  • 六、总结

前言

按照公司目前的任务,go 学习是必经之路了,虽然行业卷,不过技多不压身,依旧努力!!!
数据持久化是必不可少的一部分,平日里开发,如果是专注于业务开发,那 99% 的工作也就是CRUD(增删改查)工程师了。
废话不多说,说了也没用,直接上手来操作,对数据库进行访问。

一、简介

对数据库操作,少不了各个语言对数据库操作的驱动,就像 JAVA 中有 mysql-driver 的驱动包,拉取下来就可以通过JDBC 对数据库操作了,当然 Spring、Mybatis 等框架也提供了对数据库很方便的操作。
那在 Go 中也是提供了驱动 github.com/go-sql-driver/mysql,我们通过 go get 拉取驱动来进行CRUD操作。
使用命令:go get github.com/go-sql-driver/mysql 来拉取驱动库。

二、准备操作

首先在 MYSQL 数据库创建一个测试库叫 go_demo,然后来添加一张 User 表来操作,脚本如下:

  • 新建表:
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `address` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `age` int(0) NULL DEFAULT NULL,
	`create_time` date NOT NULL,
	`update_time` date NOT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
  • 插入测试数据
INSERT INTO `users` (name, address, age, create_time, update_time) VALUES ('悟空', '五指山下', 18, NOW(), NOW());
INSERT INTO `users` (name, address, age, create_time, update_time) VALUES ('唐僧', '大唐东土', 21, NOW(), NOW());
INSERT INTO `users` (name, address, age, create_time, update_time) VALUES ('八戒', '高老庄', 19, NOW(), NOW());
INSERT INTO `users` (name, address, age, create_time, update_time) VALUES ('沙森', '流沙河', 25, NOW(), NOW());
  • 查询数据
select * from users;

三、Insert 操作

下面的示例中,首先使用 database/sqlgithub.com/go-sql-driver/mysql 包来连接 MySQL 数据库,获取到一个连接示例 db, 再通过 db.Exec() 函数来执行 insert 语句,成功把 白龙马 指派到了师徒四人的队伍中。

package main

import (
	"database/sql"
	"fmt"
	"log"
	"time"

	_ "github.com/go-sql-driver/mysql"
)

func main() {
	// 连接 MYSQL 数据库
	db, err := sql.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/go_demo")
	if err != nil {
		log.Fatal(err)
	}
	// defer 关键字来延迟关闭连接
	defer db.Close()

	// 插入数据
	insertSql := "INSERT INTO users (name, address, age, create_time, update_time) VALUES (?, ?, ?, ?, ?)"
	datetime := time.Now()
	_, insertErr := db.Exec(insertSql, "白龙马", "东海", 18, datetime, datetime)
	if insertErr != nil {
		log.Fatal(insertErr)
	}
	fmt.Println("插入数据成功!")
}

四、Delete 操作

下面的示例中,首先使用 database/sqlgithub.com/go-sql-driver/mysql 包来连接 MySQL 数据库,获取到一个连接示例 db, 再通过 db.Exec() 函数来执行 delete 语句,成功把 悟空 逐出了队伍。
可以看出来,从获取数据库连接到执行 SQL 语句,Go 代码基本一样的,想必定有框架做了此事了……

package main

import (
	"database/sql"
	"fmt"
	"log"

	_ "github.com/go-sql-driver/mysql"
)

func main() {
	// 连接mysql数据库
	db, err := sql.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/go_demo")
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	//删除悟空
	deleteSql := "delete from users where id = ?"
	_, deleteErr := db.Exec(deleteSql, 1)
	if deleteErr != nil {
		log.Fatal(deleteErr)
	}
	fmt.Println("删除成功!")
}

五、Update 操作

更新操作其实无外乎也是获取数据库连接,执行 update 语句,我们可以先封装一个公共的函数来获取数据库连接,在执行操作。

5.1 获取数据库链接

这里的包是 common, 在另一个包中,并且 Conn 首字母大写,表明外部包是可以调用的。

package common

import (
	"database/sql"
	"log"

	_ "github.com/go-sql-driver/mysql"
)

func Conn() *sql.DB {
	// 连接mysql数据库
	db, err := sql.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/go_demo")
	if err != nil {
		log.Fatal(err)
	}
	return db
}

5.2 更新操作

下面案例,从上面封装的 common 包中通过 Conn() 函数获取数据库连接,再进行操作。
**注意:**这里需要用 common.Conn() 获取连接,不能用 *common.Conn() 获取,如果用 *common.Conn() 获取则在 后续的判断中 db != nil 出错:mismatched types sql.DB and untyped nil,因为db是一个指针类型,不能直接与 nil 进行比较。

package main

import (
	"fmt"
	"log"

	"gotest.com/test/src/common"
)

func main() {
	// 获取数据库连接
	db := common.Conn()

	if db != nil {
		defer db.Close()

		// 更新八戒的地址,不再是高老庄
		updateSql := "update users set address = ? where id = ?"
		_, updateErr := db.Exec(updateSql, "天上人间", 3)
		if updateErr != nil {
			log.Fatal(updateErr)
		}
		fmt.Println("更新成功!")
	} else {
		fmt.Println("获取数据库连接失败!")
	}
}

六、Select 操作

在下面的案例中:

  • 通过 自己封装的 common.Conn() 获取一个数据库链接
  • 利用 defer 关键词来延迟关闭链接
  • 通过 db.Query() 来执行一个查询
  • 循环遍历,rows.Next() 来判断是否有下一条记录,如果返回 true,大括号{}表示一个代码块,其中包含了每次迭代式要执行的代码。
  • {}中,可以对每条记录进行操作,比如利用 Scan() 来扫描将记录的值赋值给相应定义的变量。
  • 主要注意的是,rows.Scan(&id, &name…) 是指向 id、name 变量的指针,才能把记录中的值赋值给当前的变量。
package main

import (
	"fmt"
	"log"

	"gotest.com/test/src/common"
)

func main() {
	// 获取数据库连接
	db := common.Conn()

	selectSql := "select id,name,address,age from users"
	rows, err := db.Query(selectSql)
	if err != nil {
		log.Fatal(err)
	}
	// 延迟关闭数据库连接
	defer db.Close()

	// 遍历结果, rows是数据库查询结果的迭代器,Next()函数来判断是否下一条记录
	for rows.Next() {
		var id int
		var name string
		var address string
		var age int
		err := rows.Scan(&id, &name, &address, &age)
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println("id:", id, "name:", name, "address:", address, "age:", age)
	}
}

五、事务

下面示例中,使用db.Begin()来开启事务,本来要更新唐僧的地址为女儿国,唐僧也对女儿国王动心了,本来和女儿国王都说好了,玉帝哥哥陪国王白头到老(没头发如何白头到老),但是贫僧有要事在身,不得不离开,所以即便更新成功了,也得通过tx.Rollback()回滚回去。

package main

import (
	"fmt"
	"log"

	"gotest.com/test/src/common"
)

func main() {
	// 获取数据库连接
	db := common.Conn()

	if db != nil {
		defer db.Close()
		// 开启事务
		tx, beginErr := db.Begin()
		if beginErr != nil {
			log.Fatal(beginErr)
		}
		// 更新唐僧的地址,不再是东土大唐,留在了女儿国
		// 注意,这里要用事务 tx.Exec() 来执行操作
		updateSql := "update users set address = ? where id = ?"
		result, updateErr := db.Exec(updateSql, "女儿国", 2)
		count, _ := result.RowsAffected()
		// 如果影响行数大于 0
		if count > 0 {
			// 唐僧有使命在身,怎能为了儿女私情误了朕的大事
			tx.Rollback()
			fmt.Println("唐僧最终离开了女儿国!")
			return
		}
		if updateErr != nil {
			log.Fatal(updateErr)
			// 更新操作发生异常,事务回滚
			tx.Rollback()
		}
		// 提交事务
		commitErr := tx.Commit()
		if commitErr != nil {
			log.Fatal(commitErr)
			fmt.Println("更新提交失败!")
		}
		fmt.Println("更新成功!")
	} else {
		fmt.Println("获取数据库连接失败!")
	}
}

  • 运行前数据库记录如下:
    修改前
  • 运行结果如下:

可以看到,更新条数是 1,说明更新成功了!!!

PS D:\workspaceGo\src\database> go run .\updateTest.go
更新条数: 1
唐僧最终离开了女儿国!
2023/08/19 21:29:26 sql: transaction has already been committed or rolled back
exit status 1
  • 运行后数据库记录如下:
    运行后

注意:在使用 tx, beginErr := db.Begin()开启事务后,需要用 tx.Exec()来执行更新操作,这样后续的tx.Rollback()tx.Commit()操作才会生效。刚开始我就使用了db.Exec()来执行的更新操作,结果回滚就不生效,才发现犯了这等低级错误…

六、总结

此篇只对 Go 语言操作数据库进行简单的 CRUD 操作的示例,就像 JAVA 中用 JDBC 查库那样的基础操作,可发现基本就是通过获取的数据库链接通过函数进行对SQL的执行操作。

那 Go 操作 MySQL 有哪些优势呢?

  1. 高性能:Go 语言本身的设计目标就是高性能,所以也能够获得高性能的表现。
  2. 并发支持:Go 语言天生支持并发,可以轻松的实现并发的数据库操作,更加适合高并发的操作。
  3. 直接访问数据库:Go 语言通过标准库database/sql对SQL数据库直接访问的接口,允许直接操作数据库。

有哪些缺点呢?

  1. 生态系统相对较新:相对于其他语言,Go 语言在社区和工具等相对较新,不是很全面。
  2. ORM 支持有限:Go 语言的 ORM(对象关系映射)相对与其他语言成熟度较低,需要手动编写SQL更多。

第三方开源库用于操作 MySQL 数据库:

  1. database/sql:Go 语言标准库提供了database/sql包,支持多种数据库的操作。它提供了通用的接口的方法,让你能够进行基本的数据库操作。
  2. github.com/go-sql-driver/mysql:这是一个 MySQL 驱动,对 MySQL 数据库进行操作。
  3. github.com/jinzhu/gorm:GORM 是 Go 语言中一个流行的 ORM 框架,它 提供了对数据库的高级抽象,支持多种数据库。它可以简化数据库的操作,但是性能上有些损耗。
  4. github.com/go-xorm/xorm:XORM 是一个流行的 ORM 框架,它提供了对多种数据库的支持。它有一些独特的特性,适用于一些特定的场景。
  5. github.com/jmoiron/sqlx: SQLx 是 database/sql 的扩展,提供更方便的数据库操作方法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/81127.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

VS2019生成的DLL,给QT(MinGW版本)使用的小结

VS2019端: a 基于生成一个DLL的工程(要注意生成是x86,还是x64的,需要和后面的QT的App工程对应),这里不多解释了,网上多的是; b 在cpp实现文件里,假如要导出一个这样的…

React Native文本添加下划线

import { StyleSheet } from react-nativeconst styles StyleSheet.create({mExchangeCopyText: {fontWeight: bold, color: #1677ff, textDecorationLine: underline} })export default styles

kafka-- kafka集群 架构模型职责分派讲解

一、 kafka集群 架构模型职责分派讲解 生产者将消息发送到相应的Topic,而消费者通过从Topic拉取消息来消费 Kafka奇数个节点消费者consumer会将消息拉去过来生产者producer会将消息发送出去数据管理 放在zookeeper

actuator/prometheus使用pushgateway上传jvm监控数据

场景 准备 prometheus已经部署pushgateway服务&#xff0c;访问{pushgateway.server:9091}可以看到面板 实现 基于springboot引入支持组件&#xff0c;版本可以 <!--监控检查--><dependency><groupId>org.springframework.boot</groupId><artifa…

java Spring Boot yml多环境拆分文件管理优化

上文 java Spring Boot yml多环境配置 我们讲了多环境开发 但这种东西都放在一起 还是非常容易暴露信息的 并且对维护来讲 也不是非常的友好 这里 我们在resources下创建三个文件 分别叫 application-pro.yml application-dev.yml application-test.yml 我们直接将三个环境 转…

Seaborn数据可视化(一)

目录 1.seaborn简介 2.Seaborn绘图风格设置 21.参数说明&#xff1a; 2.2 示例&#xff1a; 1.seaborn简介 Seaborn是一个用于数据可视化的Python库&#xff0c;它是建立在Matplotlib之上的高级绘图库。Seaborn的目标是使绘图任务变得简单&#xff0c;同时产生美观且具有信…

图像处理常见的两种拉流方式

传统算法或者深度学习在进行图像处理之前&#xff0c;总是会首先进行图像的采集&#xff0c;也就是所谓的拉流。解决拉流的方式有两种&#xff0c;一个是直接使用opencv进行取流&#xff0c;另一个是使用ffmpeg进行取流&#xff0c;如下分别介绍这两种方式进行拉流处理。 1、o…

mybatis入门的环境搭建及快速完成CRUD(增删改查)

又是爱代码的一天 一、MyBatis的介绍 ( 1 ) 背景 MyBatis 的背景可以追溯到 2002 年&#xff0c;当时 Clinton Begin 开发了一个名为 iBATIS 的持久化框架。iBATIS 的目标是简化 JDBC 编程&#xff0c;提供一种更直观、易用的方式来处理数据库操作。 在传统的 JDBC 编程中&…

DevOps系列文章之 GitlabCICD自动化部署SpringBoot项目

一、概述 本文主要记录如何通过Gitlab CI/CD自动部署SpringBoot项目jar包。 二、前期准备 准备三台 CentOS7服务器&#xff0c;分别部署以下服务&#xff1a; 序号系统IP服务1CentOS7192.168.56.10Gitlab2CentOS7192.168.56.11Runner &#xff08;安装Docker&#xff09;3Cen…

对前端PWA应用的部分理解和基础Demo

一、什么是PWA应用&#xff1f; 1、PWA简介 ​ 渐进式Web应用&#xff08;Progressive Web App&#xff09;&#xff0c;简称PWA&#xff0c;是 Google 在 2015 年提出的一种使用web平台技术构建的应用程序&#xff0c;官方认为其核心在于Reliable&#xff08;可靠的&#xf…

华为ENSP网络设备配置实战4(OSPF+BGP+VPN+单臂路由)

题目要求 1、loopback口通过OSPF连通&#xff0c;合理规划OSPF开销&#xff0c;通过设置AR1->AR2->AR4链路&#xff0c;来消除负载链路。 2、AR3、AR4分别与AR1、AR2建立BGP邻居 3、AR3、AR4作为PC机网关设备 4、PC1、PC3由VPN-spi承载&#xff0c;PC2、PC4由VPN-spims承…

物联网智慧安防实训综合实训基地建设方案

一、系统概述 物联网智慧安防实训综合实训基地是一个为学生提供综合实践、培养技能的场所&#xff0c;专注于物联网技术与智慧安防应用的培训和实训。通过物联网智慧安防实训综合实训基地的建设和运营&#xff0c;学生可以在真实的环境中进行实践训练&#xff0c;提高其物联网技…

【高频面试题】 消息中间件

文章目录 1、RabbitMQ1.1 RabbitMQ-如何保证消息不丢失1.2 RabbitMQ消息的重复消费问题如何解决的1.3 RabbitMQ中死信交换机 ? (RabbitMQ延迟队列有了解过嘛)1.4 RabbitMQ如果有100万消息堆积在MQ , 如何解决(消息堆积怎么解决)1.5 RabbitMQ的高可用机制有了解过嘛 2、Kafka2.…

LlamaGPT -基于Llama 2的自托管类chatgpt聊天机器人

LlamaGPT一个自托管、离线、类似 ChatGPT 的聊天机器人&#xff0c;由 Llama 2 提供支持。100% 私密&#xff0c;不会有任何数据离开你的设备。 推荐&#xff1a;用 NSDT编辑器 快速搭建可编程3D场景 1、如何安装LlamaGPT LlamaGPT可以安装在任何x86或arm64系统上。 首先确保…

【微服务】一文了解 Nacos

一文了解 Nacos Nacos 在阿里巴巴起源于 2008 2008 2008 年五彩石项目&#xff08;完成微服务拆分和业务中台建设&#xff09;&#xff0c;成长于十年双十一的洪峰考验&#xff0c;沉淀了简单易用、稳定可靠、性能卓越的核心竞争力。 随着云计算兴起&#xff0c; 2018 2018 20…

C++11并发与多线程笔记(3)线程传参详解,detach()大坑,成员函数做线程函数

C11并发与多线程笔记&#xff08;3&#xff09;线程传参详解&#xff0c;detach 大坑&#xff0c;成员函数做线程函数 1、传递临时对象作为线程参数1.1 要避免的陷阱11.2 要避免的陷阱21.3 总结 2、临时对象作为线程参数2.1 线程id概念2.2 临时对象构造时机抓捕 3、传递类对象…

vscode 安装勾选项解释

1、通过code 打开“操作添加到windows资源管理器文件上下文菜单 &#xff1a;把这个两个勾选上&#xff0c;可以对文件使用鼠标右键&#xff0c;选择VSCode 打开。 2、将code注册为受支持的文件类型的编辑器&#xff1a;不建议勾选&#xff0c;这样会默认使用VSCode打开支持的相…

虫情测报灯

在农业生产过程中&#xff0c;农作物的虫害问题永远都是放在首位的。随着现代生活科技的发展和社会进步&#xff0c;人们对物质也有了新的要求。伴随农作物品种的增加&#xff0c;农药和化肥的使用也在导致农业虫害问题日益加剧&#xff0c;在这种不良的耕作状态下&#xff0c;…

总结 TCP 协议的相关特性

TCP协议段格式: 如图, 端口号: 是其中一个重要的部分,知道端口号才能确认数据交给哪个应用程序(端口号属于传输层的概念). 4位首部长度:4bit表示的范围是0->15,在此处,单位是"4字节",因此,将这里的数值 * 4&#xff0c;才是真正的报头长度,即TCP 报头最大长度,60…

听GPT 讲Prometheus源代码--util

Prometheus的util目录包含了一些通用的工具模块,主要包含以下文件: buckets.go 这个文件定义了一些常用的指标采样值范围(Quantile buckets),如:0.001,0.01,0.05,0.5,0.9,0.95,0.99,0.999等。这些buckets常用于计算指标的分位数线。 regex.go 这个文件定义了一些正则表达式匹配…