Go操作MySQL的一篇垃圾文章

Go操作MySQL

一. 下载MySQL驱动

执行如下命令:go get -u github.com/go-sql-driver/mysql


二. 使用MySQL驱动连接数据库

首先创建一个数据库create database go_mysql_test
然后通过sql包建立连接:

package main

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

func main() {
	dsn := "username:password@tcp(host:port)/go_mysql_test"
	db, err := sql.Open("mysql", dsn) // db是一个*sql.DB类型
	if err != nil {
		panic(err)
	}
	defer db.Close()
}

需要注意的点是,虽然通过sql包建议连接,但是必要的实现是通过"github.com/go-sql-driver/mysql"来做的,应该将包导入进来并且声明为不使用_,让它的init做初始化的工作

也可以设置最大连接数,最大空闲数等:

db.SetMaxOpenConns(100)                 // 最大连接数
db.SetMaxIdleConns(100)                 // 最大空闲数
db.SetConnMaxLifetime(time.Second * 10) // 连接的最大存活时间
db.SetConnMaxIdleTime(time.Second * 5)  // 连接的最大空闲时间

四个含义可以参考这个博客:https://www.cnblogs.com/gitfong/p/13722204.html


三. CRUD

首先建立一张user表如下:

create table `user` (
	id INT PRIMARY KEY AUTO_INCREMENT,
	sex VARCHAR(2) DEFAULT '',
	name VARCHAR(10) DEFAULT ''
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

Go操作MySQL的一篇垃圾文章
同样建立一个结构相同的结构体:

type User struct {
	id   int
	sex  string
	name string
}

3.1 插入数据

通过dbExec()操作:

sql := "insert into user(sex, name) values(?,?)"
ret, err := db.Exec(sql, "男", "jerry")
if err != nil {
	fmt.Println("插入出错", err.Error())
	return
}
id, err := ret.LastInsertId()
fmt.Println(id) // 1

3.2 更新数据

仍然通过上面的方法,修改一下sql即可:

sql := `update user set sex=?, name=? where id = ?`
ret, err := db.Exec(sql, "女", "冰墩墩", 1)
if err != nil {
	fmt.Println("更新差错", err.Error())
	return
}
row, err := ret.RowsAffected()
fmt.Println(row)

3.3 删除数据

同理


3.4 查询数据

单行查询:

var user User
// 单行查询
sql := `select * from user where id = ?`
// 这里注意要Scan出来释放连接 
err = db.QueryRow(sql, 1).Scan(&user.id, &user.sex, &user.name)
if err != nil {
	fmt.Println("查询差错", err.Error())
	return
}
fmt.Println(user)

多行查询:

sql := `select * from user where id < ?`
query, err := db.Query(sql, 3)
if err != nil {
	fmt.Println("查询差错", err.Error())
	return
}
defer query.Close() // 注意关闭
for query.Next() {
	var user User
	err := query.Scan(&user.id, &user.sex, &user.name)
	if err != nil {
		fmt.Println("scan error", err.Error())
		return
	}
	fmt.Println(user)
}

四. 预处理

提前编译节省成本,并且防止SQL注入:

sql = "select * from user where id < ?"
stmt, er := db.Prepare(sql)
if err != nil {
	fmt.Println("error" , err.Error())
	return
}
defer stmt.Close() // 注意关闭
query, err := stmt.query(3) // 直接写参数即可
defer query.Close()
for query.Next() {
	// 一样的操作
}
// 增删改也一样,stmt.Exec()即可

五. 事务

过程如下:

  1. 使用db.Begin()获取一个事务
  2. 用事务代替之前的db.Exec()stmt.Query()等操作
  3. error中执行tx.Rollback()操作回滚
  4. 在最终执行tx.Commit()操作提交
tx, err := db.Begin() // 开启事务
if err != nil {
	if tx != nil {
		tx.Rollback() // 回滚
	}
	fmt.Printf("begin trans failed, err:%v\n", err)
	return
}
sql1 := "xxx"
r1, err := tx.Exec(...)
if err != nil {
	tx.Rollback()
	Log()
	return
}
sql2 := "xxx"
r2, err := tx.Exec(...)
if err != nil {
	tx.Rollback()
	Log()
	return
}

if expected {
	tx.COmmit()
} else {
	tx.Rollback()
}

六. GORM框架

gorm是一个使用Go语言编写的ORM框架,下载方式如下:
go get github.com/jinzhu/gorm

官方文档(非常好用):https://gorm.io/zh_CN/

连接MySQL:

package main

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

func main() {
	dsn := "username:password@tcp(host:port)/go_mysql_test"
	db, err := gorm.Open("mysql", dsn) // 换成gorm.Open即可
	if err != nil {
		panic(err)
	}
	defer db.Close()
}

如果想要设置MySQL的连接数等,可以用db.SetMaxIdleConns()等方法,和上面的sql包用法相同


七. GORM的模型

gorm的模型是标准的go struct,对应数据库中的一个表结构,定义方法如下:

type User struct {
	// id int64 `gorm:"cloumn:id;primarykey"` 当然也可这样指定主键
	sex  string `gorm:"column:sex"` // gorm的tag+column指定列,不屑默认蛇形命名
	name string `gorm:"column:name"`
	gorm.Model // 这个Model里面存了ID,创建时间,更新时间和删除时间
}
// 指定表名,如果不写这个方法那么默认是蛇形复数做表明,此处是users
func (user *User) TableName() string {
	return "user"
}

需要注意的是,gorm这个tag支持非常多的标签种类,但是如果不适用自动迁移和自动创建,那么大部分的东西都不需要。(不建议使用自动迁移)

自动迁移表姐结构,在运行时会根据定义的模型去修改表,如果字段少了那么之前的数据不会变,后续不会动,如果字段增加了,会补充列:

db.AutoMigrate(&User{})

九. GORM的插入操作

user := &User{Sex: "男", Name: "噜啦啦"}
result := db.Create(user) // 该方法返回三个值
// 第一个值:错误
if err := result.Error; err != nil {
	fmt.Println(err.Error())
} else {
	fmt.Println(result.RowsAffected) // 第二个值:影响行数
}
// 第三个值是LastInsertId, 在user.ID中

Go操作MySQL的一篇垃圾文章

数据量较大可以批量插入:

users := []User{{Sex: "男", Name: "噜啦啦"}, {Sex: "女", Name: "呼噜噜"}}
db.Create(&users) // 返回值与上面相同

十. GORM查询操作

var user User
if err := db.Where("sex=?", "男").First(&user).Error; err != nil {
	fmt.Println(err.Error())
}
fmt.Println(user)
users := make([]*User, 0)
var count int64
db.Where("sex=?", "男").Order("id desc").Offset(0).Limit(2).Find(&users).Offset(1).Count(&count)
for _, user := range users {
	fmt.Println(user)
}
fmt.Println(count)

十一. GORM更新操作

var user User
if err := db.Where("sex=?", "男").First(&user).Error; err != nil {
	fmt.Println(err.Error())
}
user.Sex = "女"
if err := db.Save(&user).Error; err != nil {
	fmt.Println(err.Error())
}

如果想要指定更新列的话:

db.Model(&User{}).Where("name = ?", "jerry").Update("sex", "女")

指定更新多个列:

db.Model(&user).Where("name", "jerry").Updates(User{Sex: "男"}) // User对象里面加其他属性即可,注意的是如果属性是零值,将不会发生更新

十二. GORM删除操作

if err := db.Where("sex=?", "女").Delete(&User{}).Error; err != nil {
	fmt.Println(err.Error())
}

Go操作MySQL的一篇垃圾文章
批量删除:

if err := db.Where("name in (?)", []string{"jerry", "jerry1"}).Delete(&User{}).Error; err != nil {
	fmt.Println(err.Error())
}

这里的删除都是软删除,即设置一下deleted_at字段,如果想要永久删除需要用:

db.Unscoped().Delete(&User{})

十三. GORM的事务

与原生的写法一样,获取方法是db.Begin()

上一篇:Linux安装及管理程序(rpm和yum)


下一篇:Laravel基础课 使用查询构造器更新数据