MySQL 写操作
ConnDB
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8&parseTime=True&loc=Local&timeout=%s", mysqlCon.Username, mysqlCon.Password, mysqlCon.Addr, mysqlCon.port, mysqlCon.Db, "10s")
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
log.Printf("failed to connect database, got error %v", err)
os.Exit(1)
}
if mysqlCon.BatchSize != 0 {
db = db.Session(&gorm.Session{CreateBatchSize: mysqlCon.BatchSize})
}
Create Table
Gorm 基于数据结构体创建新的数据表,表结构就是结构体结构
定义 owner 数据表,内部嵌套 gorm 模型以及自定义的三个数据类型
type Owner struct {
gorm.Model
Address string `json:"address"`
Owner string `json:"owner"`
Tokenid int64 `json:"tokenid"`
}
创建数据表或者基于结构体更新表结构(在旧表的基础上进行新增新的结构体参数)
// 基于定义的结构体创建数据表
err = db.AutoMigrate(&table.Owner{}, &table.Transfer{})
if err != nil {
log.Printf("failed to create database, got error %v", err)
return
}
Insert
Insert Owner By Struct
结构体中的主键会采用默认的递增值
var email = new(string)
*email = "string"
var ts = new(time.Time)
*ts = time.Now()
owner := table.Owner{
Address: "",
Token: 0,
Owner: table.User{
Name: "Sam",
Email: email,
Age: 18,
Birthday: ts,
},
}
result := db.Create(&owner)
log.Printf("Insert new log with ID = %d, affected rows count = %d, with err = %v", owner.ID, result.RowsAffected, result.Error)
Insert Owner By Table and Map
采用 map 插值的方式,不会补全默认主键的值
// key is the column name of the table, must equal to the struct definition
var owner = map[string]interface{}{
"Name": "Sam16",
}
result := db.Model(&table.Owner{}).Create(owner)
log.Printf("Insert new log within affected rows count = %d, with err = %v", result.RowsAffected, result.Error)
Insert Owners By Structs
Gorm 支持批量插入数据
var owners = make([]table.Owner, 0)
var owner table.Owner
var email = new(string)
*email = "string"
var ts = new(time.Time)
*ts = time.Now()
for index := 1; index < 5; index++ {
owner = table.Owner{
Address: "",
Token: int64(index),
Owner: table.User{
Name: fmt.Sprintf("%s%d", "Sam", index),
Email: email,
Age: 18,
Birthday: ts,
},
}
owners = append(owners, owner)
}
// 批量插入需要传入整个切片
result := db.Create(&owners)
log.Printf("Insert new log with affected rows count = %d, with err = %v", result.RowsAffected, result.Error)
CreateInBatches 支持传入结构体数组和单次限额执行数据的批量插入
CreateInBatches(owner, 10)- 单次插入仅操作
10条数据 - 循环多次,每次操作
10条,直到将全部owner数据插入到库
- 单次插入仅操作
func BatchInsertOwners(db *gorm.DB, owner []table.Owner, limit int) {
result := db.CreateInBatches(owner, limit)
log.Printf("Insert new log with affected rows count = %d, with err = %v", result.RowsAffected, result.Error)
}
单次操作限额可以加在连接上,直接在此次连接中进行限制
db := db.Session(&gorm.Session{CreateBatchSize: 1000})
原生 database/sql 插入(不使用 Gorm)
上面所有写操作都走 Gorm,但 Gorm 底层其实就是 database/sql + MySQL 驱动。如果你不想引入 ORM、想完全掌控 SQL,可以用标准库直接插入。
关于 database/sql 的通用机制——驱动注册(空导入 github.com/go-sql-driver/mysql)、Open 只建连接池不拨号、Ping 探活、连接池配置、占位符差异——都已在 数据库与 SQL 里集中讲解,这里不再重复,只给 MySQL 专属的写法。
连接
dsn 即上面 ConnDB 中拼接的字符串(gorm 的 mysql.Open 与 sql.Open 共用同一套 DSN 格式):
import (
"database/sql"
_ "github.com/go-sql-driver/mysql" // 注册驱动名 "mysql"
)
db, err := sql.Open("mysql", dsn)
if err != nil {
log.Printf("failed to init db: %v", err)
return
}
defer db.Close()
if err := db.Ping(); err != nil { // 真正的连通性校验,Open 不会帮你连
log.Printf("failed to ping db: %v", err)
return
}
单条插入
db.Exec 直接执行 SQL,结果用 LastInsertId()(自增主键) / RowsAffected()(受影响行数)取回,而不是 Gorm 的 result.RowsAffected:
// 参数用 ? 占位符(MySQL 语法;PostgreSQL 用 $1, $2)
result, err := db.Exec(
"INSERT INTO owners (address, owner, tokenid) VALUES (?, ?, ?)",
"0xabc", "Sam", 1,
)
if err != nil {
log.Printf("insert failed: %v", err)
return
}
id, _ := result.LastInsertId() // 自增主键
n, _ := result.RowsAffected() // 受影响行数
log.Printf("inserted id=%d, rows=%d", id, n)
批量插入(预编译 + 循环 Exec)
stmt, err := db.Prepare("INSERT INTO owners (address, owner, tokenid) VALUES (?, ?, ?)")
if err != nil {
log.Printf("prepare failed: %v", err)
return
}
defer stmt.Close()
for i := 1; i < 5; i++ {
if _, err := stmt.Exec("0xabc", fmt.Sprintf("Sam%d", i), int64(i)); err != nil {
log.Printf("exec failed at %d: %v", i, err)
}
}
要点:
- 想要 ORM 映射就用 Gorm(本页上半部分);想要完全掌控 SQL 与最小依赖就用原生
database/sql(本页本节)。 - 占位符随驱动不同而异:MySQL 用
?,PostgreSQL(pgx走database/sql)用$1/$2。通用机制见 数据库与 SQL。