前言
目前正在研究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框架去操作数据库,减少琐碎的操作,提高开发效率。
刚好想学习下go语言,看到你的文章感觉收获很多,赞~