GO学习之 数据库(mysql)

2023-10-11 21:45
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 中也是提供了驱动 www.hljyjzlw.com/go-sql-driver/mysql,我们通过 go get 拉取驱动来进行CRUD操作。 使用命令:go get www.hljyjzlw.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; 下面的示例中,首先使用 database/sql 和 www.hljyjzlw.com/go-sql-driver/mysql 包来连接 MySQL 数据库,获取到一个连接示例 db, 再通过 db.Exec() 函数来执行 insert 语句,成功把 白龙马 指派到了师徒四人的队伍中。 package mainimport ("database/sql""fmt""log""time"_ "www.hljyjzlw.com/go-sql-driver/mysql" )func main() {db, err := www.hljyjzlw.com("mysql", "root:123456@tcp(127.0.0.1:3306)/go_demo")if err != nil {log.Fatal(err)}defer db.Close()insertSql := "INSERT INTO users (name, address, age, create_time, update_time) VALUES (?, ?, ?, ?, ?)"datetime := www.hljyjzlw.com()_, insertErr := db.Exec(insertSql, "白龙马", "东海", 18, datetime, datetime)if insertErr != nil {log.Fatal(insertErr)}fmt.Println("插入数据成功!") } 下面的示例中,首先使用 database/sql 和 www.hljyjzlw.com/go-sql-driver/mysql 包来连接 MySQL 数据库,获取到一个连接示例 db, 再通过 db.Exec() 函数来执行 delete 语句,成功把 悟空 逐出了队伍。 可以看出来,从获取数据库连接到执行 SQL 语句,Go 代码基本一样的,想必定有框架做了此事了…… package mainimport ("database/sql""fmt""log"_ "www.hljyjzlw.com/go-sql-driver/mysql" )func main() {db, err := www.hljyjzlw.com("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 语句,我们可以先封装一个公共的函数来获取数据库连接,在执行操作。 5.1 获取数据库链接 这里的包是 common, 在另一个包中,并且 Conn 首字母大写,表明外部包是可以调用的。 package commonimport ("database/sql""log"_ "www.hljyjzlw.com/go-sql-driver/mysql" )func Conn() *sql.DB {db, err := www.hljyjzlw.com("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 mainimport ("fmt""log""www.hljyjzlw.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("获取数据库连接失败!")} } 在下面的案例中: 通过 自己封装的 common.Conn() 获取一个数据库链接利用 defer 关键词来延迟关闭链接通过 db.Query() 来执行一个查询循环遍历,www.hljyjzlw.com() 来判断是否有下一条记录,如果返回 true,大括号{}表示一个代码块,其中包含了每次迭代式要执行的代码。在{}中,可以对每条记录进行操作,比如利用 Scan() 来扫描将记录的值赋值给相应定义的变量。主要注意的是,rows.Scan(&id, &name…) 是指向 id、name 变量的指针,才能把记录中的值赋值给当前的变量。 package mainimport ("fmt""log""www.hljyjzlw.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()for www.hljyjzlw.com() {var id intvar name stringvar address stringvar age interr := 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 mainimport ("fmt""log""www.hljyjzlw.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)}updateSql := "update users set address = ? where id = ?"result, updateErr := db.Exec(updateSql, "女儿国", 2)count, _ := result.RowsAffected()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 有哪些优势呢? 高性能:Go 语言本身的设计目标就是高性能,所以也能够获得高性能的表现。并发支持:Go 语言天生支持并发,可以轻松的实现并发的数据库操作,更加适合高并发的操作。直接访问数据库:Go 语言通过标准库database/sql对SQL数据库直接访问的接口,允许直接操作数据库。 有哪些缺点呢? 生态系统相对较新:相对于其他语言,Go 语言在社区和工具等相对较新,不是很全面。ORM 支持有限:Go 语言的 ORM(对象关系映射)相对与其他语言成熟度较低,需要手动编写SQL更多。 第三方开源库用于操作 MySQL 数据库: database/sql:Go 语言标准库提供了database/sql包,支持多种数据库的操作。它提供了通用的接口的方法,让你能够进行基本的数据库操作。www.hljyjzlw.com/go-sql-driver/mysql:这是一个 MySQL 驱动,对 MySQL 数据库进行操作。www.hljyjzlw.com/jinzhu/gorm:GORM 是 Go 语言中一个流行的 ORM 框架,它 提供了对数据库的高级抽象,支持多种数据库。它可以简化数据库的操作,但是性能上有些损耗。www.hljyjzlw.com/go-xorm/xorm:XORM 是一个流行的 ORM 框架,它提供了对多种数据库的支持。它有一些独特的特性,适用于一些特定的场景。www.hljyjzlw.com/jmoiron/sqlx: SQLx 是 database/sql 的扩展,提供更方便的数据库操作方法。