Go操作MySQL
- 一. 下载MySQL驱动
- 二. 使用MySQL驱动连接数据库
- 三. CRUD
- 四. 预处理
- 五. 事务
- 六. GORM框架
- 七. GORM的模型
- 九. GORM的插入操作
- 十. GORM查询操作
- 十一. GORM更新操作
- 十二. GORM删除操作
- 十三. GORM的事务
一. 下载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;
同样建立一个结构相同的结构体:
type User struct {
id int
sex string
name string
}
3.1 插入数据
通过db
的Exec()
操作:
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()即可
五. 事务
过程如下:
- 使用
db.Begin()
获取一个事务 - 用事务代替之前的
db.Exec()
和stmt.Query()
等操作 - 在
error
中执行tx.Rollback()
操作回滚 - 在最终执行
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中
数据量较大可以批量插入:
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())
}
批量删除:
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()