执行如下命令:go get -u github.com/go-sql-driver/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
首先建立一张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 }
通过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
仍然通过上面的方法,修改一下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)
同理
单行查询:
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是一个使用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
的模型是标准的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{})
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) // 返回值与上面相同
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)
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对象里面加其他属性即可,注意的是如果属性是零值,将不会发生更新
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{})
与原生的写法一样,获取方法是db.Begin()