评论

Go学习笔记——原生Go语言操作MySQL数据库

本文介绍了如何使用原生的Go语言连接并操作数据库

前言

目前正在研究Go的后端开发技术,而连接并操作数据库是后端工作中非常重要的一环。故练习了一下用Go语言操作数据库的方法,借此来进一步打好Go语言的开发基础。

1. 创建数据库和数据表

为了方便学习和测试,在MySQL中创建名叫test的数据库和user的数据表,并插入三条数据进行初始化

# 创建名为test的数据库
CREATE DATABASE test;
# 进入到刚刚创建的数据库
use test;
# 创建user数据表
CREATE TABLE user (
id int primary key not null auto_increment,
name varchar(20) default '',
phone varchar(20) default '');
# 插入测试数据
insert into user values(1,'zhangsan','111111'), (2,'lisi','123123'), (3,'wangwu','121212');

MySQL控制台中查看插入的结果

2. 使用MySQL驱动程序

如果是在电脑上第一次使用,则需要通过以下命令先下载依赖包

go get -u github.com/go-sql-driver/mysql

导入依赖包如下

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

"github.com/go-sql-driver/mysql"就是依赖包。因为没有直接使用该包中的对象,所以导入包前面被加了下划线( _ )

3. 连接数据库

Go语言database/sql包中提供了Open()函数,用来连接数据库。定义如下

func Open(driverName, dataSourceName string) (*DB, error)

参数driverName用于指定数据库;
dataSourceName用于指定数据源,格式一般为[username]:[password]@tcp(127.0.0.1:3306)/[databaseName]
代码如下

var db *sql.DB = new(sql.DB)

func initDB() (err error) {
	// 用户名为root,密码为root,连接到MySQL中的test数据库
	db, err = sql.Open("mysql", "root:root@tcp(127.0.0.1:3306)/test")
	if err != nil {
		return err
	}
	err = db.Ping()
	if err != nil {
		return err
	}
	return nil
}

4. 操作数据库

在操作之前,根据数据表中的信息对查询结果进行封装

type User struct {
	Id    int
	Name  string
	Phone string
}

var u *User = new(User)

4.1. 查询操作

查询操作分为单行查询和多行查询,Go中定义的函数如下

// 单行查询
func (db *DB) QueryRow(query string, args ...interface{}) *Row
// 多行查询
func (db *DB) Query(query string, args ...interface{}) *Rows

参数query代表SQL语句,args表示query中的占位参数
具体操作如下:

4.1.1. 单行查询

代码

func queryRow() {
	// 该查询语句等价于select id,name,phone from user where id = 1;
	err := db.QueryRow("select id,name,phone from `user` where id=?", 1).Scan(&u.Id, &u.Name, &u.Phone)
	if err != nil {
		fmt.Printf("scan failed, err: %v\n", err)
		return
	}
	fmt.Println("query success!")
	fmt.Printf("id: %d, name: %s, phone: %s\n", u.Id, u.Name, u.Phone)
}

结果

4.1.2. 多行查询

代码

func queryMultiRow() {
	rows, err := db.Query("select * from user")
	if err != nil {
		fmt.Println("query failed, err:%v\n", err)
		return
	}
	defer rows.Close()
	fmt.Println("query success!")
	for rows.Next() {
		err := rows.Scan(&u.Id, &u.Name, &u.Phone)
		if err != nil {
			fmt.Printf("scan failed, err:%v\n", err)
			return
		}
		fmt.Printf("id: %d, name: %s, phone: %s\n", u.Id, u.Name, u.Phone)
	}
}

结果

4.2. 插入操作

Exec()方法可以用来执行插入操作。注意:插入、更新和删除都是使用此方法

func (db *DB) Exec(query string, args ...interface{}) (Result, error)

返回的Result是对SQL命令的执行结果

代码

func insertRow() {
	ret, err := db.Exec("insert into user(name, phone) values (?,?)", "zhaoliu", "123456")
	if err != nil {
		fmt.Printf("insert failed, err:%v\n", err)
		return
	}
	id, err := ret.LastInsertId()
	if err != nil {
		fmt.Printf("get lastinsert ID failed, err:%v\n", err)
		return
	}
	fmt.Printf("insert success, the id is %d\n", id)
}

代码输出的结果

在MySQL控制台中查看结果

4.3. 更新操作

代码

func updateRow() {
	ret, err := db.Exec("update user set name = ? where id = ?", "Tom", 1)
	if err != nil {
		fmt.Printf("update failed, errr:%v\n", err)
		return
	}
	n, err := ret.RowsAffected()
	if err != nil {
		fmt.Printf("get RowsAffected failed, err:%v\n", err)
		return
	}
	fmt.Printf("update success, affected rows: %d\n", n)
}

代码输出结果

在MySQL控制台中查看结果

4.4. 删除操作

代码

func deleteRow() {
	ret, err := db.Exec("delete from user where id = ?", 2)
	if err != nil {
		fmt.Printf("delete failed, err:%v\n", err)
		return
	}
	n, err := ret.RowsAffected()
	if err != nil {
		fmt.Printf("get RowsAffected failed, err:%v\n", err)
		return
	}
	fmt.Printf("delete success, affected rows:%d\n", n)
}

代码输出结果

在MySQL控制台中查看结果

5. 完整代码

package main

import (
	"fmt"
	"database/sql"
	_ "github.com/go-sql-driver/mysql"
)

var db *sql.DB = new(sql.DB)

func initDB() (err error) {
	db, err = sql.Open("mysql", "root:root@tcp(127.0.0.1:3306)/test")
	if err != nil {
		return err
	}
	err = db.Ping()
	if err != nil {
		return err
	}
	return nil
}

type User struct {
	Id    int
	Name  string
	Phone string
}

var u *User = new(User)

func queryRow() {
	// 该查询语句等价于select id,name,phone from user where id = 1;
	err := db.QueryRow("select id,name,phone from `user` where id=?", 1).Scan(&u.Id, &u.Name, &u.Phone)
	if err != nil {
		fmt.Printf("scan failed, err: %v\n", err)
		return
	}
	fmt.Println("query success!")
	fmt.Printf("id: %d, name: %s, phone: %s\n", u.Id, u.Name, u.Phone)
}

func queryMultiRow() {
	rows, err := db.Query("select * from user")
	if err != nil {
		fmt.Println("query failed, err:%v\n", err)
		return
	}
	defer rows.Close()
	fmt.Println("query success!")
	for rows.Next() {
		err := rows.Scan(&u.Id, &u.Name, &u.Phone)
		if err != nil {
			fmt.Printf("scan failed, err:%v\n", err)
			return
		}
		fmt.Printf("id: %d, name: %s, phone: %s\n", u.Id, u.Name, u.Phone)
	}
}

func insertRow() {
	ret, err := db.Exec("insert into user(name, phone) values (?,?)", "zhaoliu", "123456")
	if err != nil {
		fmt.Printf("insert failed, err:%v\n", err)
		return
	}
	id, err := ret.LastInsertId()
	if err != nil {
		fmt.Printf("get lastinsert ID failed, err:%v\n", err)
		return
	}
	fmt.Printf("insert success, the id is %d\n", id)
}

func updateRow() {
	ret, err := db.Exec("update user set name = ? where id = ?", "Tom", 1)
	if err != nil {
		fmt.Printf("update failed, errr:%v\n", err)
		return
	}
	n, err := ret.RowsAffected()
	if err != nil {
		fmt.Printf("get RowsAffected failed, err:%v\n", err)
		return
	}
	fmt.Printf("update success, affected rows: %d\n", n)
}

func deleteRow() {
	ret, err := db.Exec("delete from user where id = ?", 2)
	if err != nil {
		fmt.Printf("delete failed, err:%v\n", err)
		return
	}
	n, err := ret.RowsAffected()
	if err != nil {
		fmt.Printf("get RowsAffected failed, err:%v\n", err)
		return
	}
	fmt.Printf("delete success, affected rows:%d\n", n)
}

func main() {
	err := initDB()
	if err != nil {
		fmt.Printf("init db failed, err: %v\n", err)
		return
	}
	queryRow()
	queryMultiRow()
	insertRow()
	updateRow()
	deleteRow()
}

6. 总结

原生Go语言操作数据库并不难,但有不少细节的地方要注意,比如错误处理、内存分配和资源释放等。故原生Go语言操作数据库的操作适合用来巩固基础,培养工程思维;在实际后台开发中,几乎都是使用封装好的orm框架去操作数据库,减少琐碎的操作,提高开发效率。

最后一次编辑于  2021-11-12  
点赞 1
收藏
评论

1 个评论

  • 知非
    知非
    2021-11-14

    刚好想学习下go语言,看到你的文章感觉收获很多,赞~

    2021-11-14
    赞同 1
    回复 2
    • 晨曦
      晨曦
      2021-11-14
      我现在就在学go语言,后面还会继续分享有关内容的。可以多多交流呀~~
      2021-11-14
      1
      回复
    • 知非
      知非
      2021-11-14回复晨曦
      好的,期待你的下篇文章~
      2021-11-14
      1
      回复
登录 后发表内容