Go数据库操作
本人编写了一个根据数据库表单生成表单的工具,欢迎自取:gitee->gorm结构体自动生成工具
前期操作
下载驱动包:
go get github.com/go-sql-driver/mysql
最后导入包即可:
import "database/sql"
import _ "github.com/go-sql-driver/mysql"
连接到数据库:
db, err := sql.Open("mysql", "username:password@tcp(localhost:3306)/database")
if nil != err {
fmt.Println("connect db error: ", err)
}
defer db.Close()
db.SetMaxOpenConns(10) // 设置最大连接数
db.SetMaxIdleConns(5) // 设置闲置情况最大连接数
CRUD操作
查询操作:
// 指定条件,指定参数查询
rows, err := db.Query("select * from book where id=?", 12312)
if nil != err {
fmt.Println("query db error: ", err.Error())
return
}
defer rows.Close()
fmt.Println(rows)
for rows.Next() {
var book dao.Book\
err = rows.Scan(&book.Id, &book.Title)
if err != nil {
panic(err.Error())
}
fmt.Println(book)
}
增、删、改操作:
// 增加
insert := "insert into book(title) values(?)"
ret, err := db.Exec(insert, "name")
if err != nil {
println(err.Error())
return
}
id, err := ret.LastInsertId()
if err != nil {
fmt.Println("获取id失败")
return
}
fmt.Print("插入的id为:", id)
// 修改
update := "update book set title = ? where id = ?"
uret, err := db.Exec(update, "hello", id)
if err != nil {
fmt.Println(err.Error())
return
}
unum, err := ret.RowsAffected()
if err != nil {
fmt.Println(err.Error())
return
}
fmt.Printf("影响了 %d 行数据\n", unum)
// 删除
del := "delete from book where title = ?"
dret, err := db.Exec(del, "hello")
if err != nil {
fmt.Println(err.Error())
return
}
dnum, err = dret.RowsAffected()
if err != nil {
fmt.Println(err.Error())
return
}
fmt.Printf("影响了 %d 行数据\n", dnum)
预编译
sql := "select * from book where id = ?"
stmt, err := db.Prepare(sql)
defer stmt.Close()
rows, err := stmt.Query(1)
fmt.Println(rows)
for rows.Next() {
var book dao.Book
//将值存入变量book中
err = rows.Scan(&book.Id, &book.Title)
if err != nil {
//panic(err.Error())
}
fmt.Println(book)
}
Gorm框架应用
建议学习官方文档更详细:gorm.io官方
连接数据库:
核心代码(需要导入包):
package database
import (
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
var Db *gorm.DB
func Init() {
var err error
dataConfig := "username:password@tcp(localhost:3306)/gostudy"
Db, err = gorm.Open("mysql", dataConfig)
if err != nil {
fmt.Printf("mysql connect error %v", err)
}
defer Db.Close()
Db.DB().SetMaxOpenConns(10) // 设置最大连接数
Db.DB().SetMaxIdleConns(5) // 设置闲置情况最大连接数
}
模型设定
属性首字母应该是大写的,如果是小写无法反射获取,会导致映射失败
默认结构体名字对应着表名复数形式,建议自己实现func TableName() string
方法更好
package model
type Data struct {
DataId int `json:"data_id" gorm:"column:data_id;primaryKey"`
User string `json:"user" gorm:"column:user"`
Password string `json:"password" gorm:"column:password"`
}
func (e *Data) TableName() string {
return "data"
}
本人编写了一个根据数据库表单生成表单的工具,欢迎自取:gitee->gorm结构体自动生成工具
CRUD
查询
GORM 提供了 First
、Take
、Last
方法,以便从数据库中检索单个对象。当查询数据库时它添加了 LIMIT 1
条件,且没有找到记录时,它会返回 ErrRecordNotFound
错误
// 获取第一条记录(主键升序)
db.First(&user)
// SELECT * FROM users ORDER BY id LIMIT 1;
// 获取一条记录,没有指定排序字段
db.Take(&user)
// SELECT * FROM users LIMIT 1;
// 获取最后一条记录(主键降序)
db.Last(&user)
// SELECT * FROM users ORDER BY id DESC LIMIT 1;
result := db.First(&user)
result.RowsAffected // 返回找到的记录数
result.Error // returns error or nil
// 检查 ErrRecordNotFound 错误
errors.Is(result.Error, gorm.ErrRecordNotFound)
如果你想避免
ErrRecordNotFound
错误,你可以使用Find
,比如db.Limit(1).Find(&user)
,Find
方法可以接受struct和slice的数据。
**注意:**如果相关 model 没有定义主键,那么将按 model 的第一个字段进行排序。
常用方法示例:
注意筛选条件必须 放在Find()
前面
// 条件搜索
// SELECT * FROM `data` WHERE (data_id = 1)
find := Db.Where("data_id = ?", 1).Find(&d)
// find.RowsAffected 可以判断搜索到的数目
fmt.Println(find.RowsAffected)
// select选取特定字段
// SELECT user FROM `data` LIMIT 1
Db.Select("user").First(&d)
// orderBY
// SELECT * FROM `data` ORDER BY data_id
Db.Order("data_id").Find(&d)
// group 和 having
// SELECT * FROM `data` GROUP BY date(data_id) HAVING (sum(data_id) > 100)
rows, err := Db.Table("data").Group("date(data_id)").Having("sum(data_id) > ?", 100).Rows()
// 多条数据,如果不是切片只是一个,那么就只会是最后的
var ds []model.Data
Db.Where("password = ?", "123321").Find(&ds)
// rows方法扫描
var ds model.Data
rows, _ := Db.Model(&model.Data{}).Where("password = ?", "123321").Rows()
defer rows.Close() // 没读完且不关闭就会导致go太多
for rows.Next() {
Db.ScanRows(rows, &ds)
fmt.Println(ds)
}
// 如果条件不存在就插入
// SELECT * FROM `data` WHERE (data_id = 2) LIMIT 1
// INSERT INTO `data` (`da***ser`,`password`) VALUES (0,'us','2')
Db.FirstOrCreate(&d, "data_id = ?", 2)
// 自定义语句
ds := make([]model.Data, 0)
database.Db.Raw("select * from data where password = ?", 2).Scan(&ds)
插入
// 基本创建
// INSERT INTO `data` (`da***ser`,`password`) VALUES (3,'uss','123')
ds := model.Data{3, "uss", "123"}
Db.Create(&ds)
// 选择 某个字段 or 忽略
ds := model.Data{0, time.Now().String(), "1234"}
// Select 选择, 里面填的也可以是 struct的名字,不一定是数据库的(酷,好东西)
Db.Select("da***ser", "password").Create(&ds)
// Omit 忽略
ds := model.Data{0, time.Now().String(), "1234"}
Db.Omit("password").Create(&ds)
更新
// 更新
var d model.Data
Db.Model(&d).Where("data_id = ?", 1).Update("password", "hello")
// 根据 `struct` 更新属性,只会更新非零值的字段
db.Model(&user).Updates(User{Name: "hello", Age: 18, Active: false})
// UPDATE users SET name='hello', age=18, updated_at = '2013-11-17 21:34:10' WHERE id = 111;
// UPDATE `data` SET `data_id` = data_id + 2
exp := gorm.Expr("data_id + ?", 2)
Db.Table("data").Update("data_id", exp)
// 同样支持select 和 Omit,这两个方法不能配合Table用,必须配合Model!!!
d := model.Data{0, "3", "2"}
Db.Model(&model.Data{}).Select("User").Update(&d)
Db.Model(&model.Data{}).Omit("User").Update(&d)
// 使用map更新
Db.Model(&model.Data{}).Update(map[string]interface{}{"user":"s"})
注意 当通过 struct 更新时,GORM 只会更新非零字段。 如果您想确保指定字段被更新,你应该使用
Select
更新选定字段,或使用map
来完成更新操作
删除
删除的话一定要增加添加,如果本身没有设置ID
这个字段的,就算自己搞了primaryKey
都无用,还是需要Where
才可以防止删除,同时gorm提供软删除
,需要有gorm.DeletedAt
字段
// Email 的 ID 是 `10`,不建议用这个方式!
db.Delete(&email)
// DELETE from emails where id = 10;
// DELETE FROM `data` WHERE (user = 's')
Db.Where("user = ?", "s").Delete(&model.Data{})
CURD四个常用
// 查找,条件需要放在 Find() 前面
var ds []model.Data
Db.Where("password = ?", "value").Find(&ds) // 或者单个First
// 删除
Db.Where("password = ?", "value").Delete(&model.Data{})
// 更新(必须要有Model)
Db.Model(&model.Data{}).Select("User").Update(&d)
Db.Model(&model.Data{}).Where().Update(map[string]interface{}{"password":"value"})
Db.Model(&model.Data{}).Where().Update("password", "value")
// 插入
Db.Create(&d) // 配合 select & Omit
Db.FirstOrCreate(&d, "data_id = ?", 2)
// exec执行指令, 适合: 删除、更新、插入
Db.Exec("update data set password = ? where user = ?", 3, "us")
// raw则适合:查询
Db.Raw("select * from data where password = ?", 2).Scan(&ds) // 自定义语句
tag字段补充
声明 model 时,tag 是可选的,GORM 支持以下 tag: tag 名大小写不敏感,但建议使用 camelCase
风格
标签名 | 说明 |
---|---|
column | 指定 db 列名 |
type | 列数据类型,推荐使用兼容性好的通用类型,例如:所有数据库都支持 bool、int、uint、float、string、time、bytes 并且可以和其他标签一起使用,例如:not null 、size , autoIncrement … 像 varbinary(8) 这样指定数据库数据类型也是支持的。在使用指定数据库数据类型时,它需要是完整的数据库数据类型,如:MEDIUMINT UNSIGNED not NULL AUTO_INCREMENT |
size | 指定列大小,例如:size:256 |
primaryKey | 指定列为主键 |
unique | 指定列为唯一 |
default | 指定列的默认值 |
precision | 指定列的精度 |
scale | 指定列大小 |
not null | 指定列为 NOT NULL |
autoIncrement | 指定列为自动增长 |
autoIncrementIncrement | 自动步长,控制连续记录之间的间隔 |
embedded | 嵌套字段 |
embeddedPrefix | 嵌入字段的列名前缀 |
autoCreateTime | 创建时追踪当前时间,对于 int 字段,它会追踪秒级时间戳,您可以使用 nano /milli 来追踪纳秒、毫秒时间戳,例如:autoCreateTime:nano |
autoUpdateTime | 创建/更新时追踪当前时间,对于 int 字段,它会追踪秒级时间戳,您可以使用 nano /milli 来追踪纳秒、毫秒时间戳,例如:autoUpdateTime:milli |
index | 根据参数创建索引,多个字段使用相同的名称则创建复合索引,查看 索引 获取详情 |
uniqueIndex | 与 index 相同,但创建的是唯一索引 |
check | 创建检查约束,例如 check:age > 13 ,查看 约束 获取详情 |
<- | 设置字段写入的权限, <-:create 只创建、<-:update 只更新、<-:false 无写入权限、<- 创建和更新权限 |
-> | 设置字段读的权限,->:false 无读权限 |
- | 忽略该字段,- 无读写权限 |
comment | 迁移时为字段添加注释 |
常见错误
-
时间比较,记得要改格式
database.Db.Where("send_time = ?", 、sendTime.Format("2006-01-02 15:04:05")).Find(&FriendReqLog{})