gorm数据库操作
前言:
Object-Relationl Mapping,它的作用是在关系型数据库和对象之间作一个映射,这样,我们在具体的操作数据库的时候,就不需要再去和复杂的SQL语句打交道,只要像平时操作对象一样操作它就可以了 。
GORM是golang写的ORM库
正文:
GORM 官方支持的数据库类型有: MySQL, PostgreSQL, SQlite, SQL Server
安装gorm:
go get -u gorm.io/gorm
go get -u gorm.io/driver/mysql //mysql 驱动
链接mysql实例:
var db *gorm.DB var dbErr error func init() { dsn := "root:root123456@tcp(127.0.0.1:3306)/yangtest?charset=utf8" db, dbErr = gorm.Open(mysql.Open(dsn)) if dbErr != nil { log.Fatal(dbErr.Error()) } fmt.Println("mysql 连接成功") }
模型定义自动迁移tag标签
根据标签自动生成表示例:
type User struct { //gorm.Model Id int `gorm:"type:int;primary key"` Name string `gorm:"type:varchar(20);not null;index"` Email string `gorm:"type:varchar(20)"` Age int `gorm:"type:tinyint(20);unsigned"` CreateAt int64 `gorm:"type:int(20);unsigned;not null;autoCreateTime"` UpdateAt int64 `gorm:"type:int(20);unsigned;not null;autoUpdateTime;default:0"` } var db *gorm.DB var dbErr error func init() { dsn := "root:root123456@tcp(127.0.0.1:3306)/yangtest?charset=utf8" db, dbErr = gorm.Open(mysql.Open(dsn)) if dbErr != nil { log.Fatal(dbErr.Error()) } fmt.Println("mysql 连接成功") } func main() { db.Set("gorm:table_options", "ENGINE=InnoDB").AutoMigrate(&User{}) }
运行程序,即可看到数据库生成了 users表,表结构如下:
CREATE TABLE `users` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `name` varchar(20) NOT NULL, `email` varchar(20) DEFAULT NULL, `age` tinyint(20) DEFAULT NULL, `create_at` int(20) NOT NULL, `update_at` int(20) NOT NULL DEFAULT '0', PRIMARY KEY (`id`), KEY `idx_users_name` (`name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
tag标记列表:
配置表名:
默认生成的表名是 是结构体名称的复数形式,如果自定义其他表名,
就需要使用 TableName方法进行配置表名
//根据结构体自定义表名 func (u *User) TableName() string { return "user" }
全局配置表前缀及表名:
如果需要全局表名不加复数,以及全局增加表前缀,就在连接数据库的时候进行全局配置
func init() { dsn := "root:root123456@tcp(127.0.0.1:3306)/yangtest?charset=utf8" db, dbErr = gorm.Open(mysql.Open(dsn), &gorm.Config{ //全局配置 NamingStrategy: schema.NamingStrategy{ SingularTable: true, //表名不增加复数 TablePrefix: "shop_", //增加表前缀 }, }) if dbErr != nil { log.Fatal(dbErr.Error()) } }
gorm操作数据库增删改查
插入数据:
func InsertData() { user := User{Name: "lampol44", Age: 23, Email: "3333333@qq.com"} //res := db.Create(&user) //fmt.Println(res.RowsAffected, res.Error, user.Id) //输出1 <nil> 1 //插入字段插入 //res := db.Select("name", "age").Create(&user) //fmt.Println(res.RowsAffected, res.Error, user.Id) //排除某字段插入 res := db.Omit("email").Create(&user) fmt.Println(res.RowsAffected, res.Error, user.Id) }
批量插入数据:
func InsertDataMul() { //定义一个结构体数组 user := []User{ {Name: "lampol3", Age: 23, Email: "333333333@qq.com"}, {Name: "lampol4", Age: 24, Email: "444444444@qq.com"}, {Name: "lampol5", Age: 25, Email: "555555555@qq.com"}, {Name: "lampol6", Age: 26, Email: "666666666@qq.com"}, } res := db.Create(&user) fmt.Println(res.RowsAffected, res.Error) }
使用map单条插入数据:
使用map的话,因为没有标签,不会自动生成 create_at 字段,也无法获取到插入的id
所以不建议使用map作为插入数据的参数
func InsertData() { var user map[string]interface{} user = make(map[string]interface{}) user["name"] = "lampol8" user["age"] = 55 user["email"] = "8888888@qq.com" user["create_at"] = time.Now().Unix() //res := db.Model(&User{}).Create(&user) res := db.Table("users").Create(&user) fmt.Println(user) fmt.Println(res.RowsAffected, res.Error) }
如果不写入 create_at 会报错
查询数据
First,Last,Take
使用结构体接收数据:
var user User //获取第一条数据 db.First(&user) fmt.Println(user) //获取第一条数据 db.Take(&user) fmt.Println(user) //获取最后一条数据 db.Last(&user) fmt.Println(user)
使用map接收数据:
var data = map[string]interface{}{} db.Model(&User{}).First(&data) fmt.Println(data) db.Model(&User{}).Take(&data) fmt.Println(data) db.Model(&User{}).Last(&data) fmt.Println(data) fmt.Println(data["id"])
使用take获取ID为6的数据
var user User db.Take(&user, 6) fmt.Println(user)
使用take获取name为lampol6的数据
//查询 name 为 lampol5的记录 var user User db.Take(&user, "name", "lampol6") fmt.Println(user)
查询多条数据
使用find查询全部数据
var users []User db.Find(&users) fmt.Println(users)
使用find查询多条ID的数据
var users []User db.Find(&users, []int{3, 4, 5, 6, 7}) fmt.Println(users)
使用scan查询多条数据
var users []User db.Model(&User{}).Scan(&users) fmt.Println(users)
使用find根据条件查询多条
var users []User //一个条件 db.Find(&users, "age=?", 26) fmt.Println(users) //多个条件 db.Find(&users, User{ Name: "lampol6", Age: 26, }) fmt.Println(users)
使用where查询多条
var users []User //单个where查询 db.Where("age=?", 26).Find(&users) fmt.Println(users) //多个where查询 db.Where("age=?", 26).Where("name=?", "lampol6").Find(&users) fmt.Println(users) //不等于查询 db.Where("age<>?", 26).Find(&users) fmt.Println(users) //in查询 db.Where("name in ?", []string{"lampol4", "lampol5"}).Find(&users) fmt.Println(users) //select查询指定字段 db.Select([]string{"name", "age"}).Where("name in ?", []string{"lampol4", "lampol5"}).Find(&users) fmt.Println(users) //排序 order 和 limit db.Where("age=?", 26).Order("id DESC").Limit(2).Find(&users) fmt.Println(users)
多表,连表查询:
type OrderList struct { Name string GoodsName string } var userOrder []OrderList db.Table("shop_user").Select("shop_user.name", "shop_order_list.goods_name"). Joins("join shop_order_list on shop_user.id=shop_order_list.user_id").Find(&userOrder) fmt.Println(userOrder)
查询数量:
var count int64 //db.Model(&User{}).Where("age=?", 26).Count(&count) db.Table("shop_user").Where("age=?", 26).Count(&count) fmt.Println(count)
更新数据:
//更新数据 res := db.Model(&User{}).Where("id=?", 5).Update("age", 45) fmt.Println(res.RowsAffected) //更新多个字段 res := db.Model(&User{}).Where("id=?", 6).Updates(&User{Name: "yangphp", Age: 32}) fmt.Println(res.RowsAffected) //查询出来,然后使用save更新 var user User db.First(&user) user.Age = 44 user.Name = "lampol_88" db.Save(&user) //原生sql更新 db.Exec("UPDATE shop_user SET name=?", "lampol") //删除 //db.Delete(&User{}, 5) //删除一条 db.Delete(&User{}, []int{6, 7}) //删除多条
原生sql增删查改:
//插入数据 db.Exec("INSERT INTO shop_user (name,age,email,is_sex) VALUES(?,?,?,?)", "lampol_4", 55, "123@qq.com", 1) //更新 res := db.Exec("UPDATE shop_user SET name=? WHERE id=?", "lampol_2", 5) //更新, expr做计算 db.Exec("UPDATE shop_user SET age=? WHERE id=?", gorm.Expr("age+?", 5), 5) //删除 res := db.Exec("DELETE FROM shop_user WHERE id=?", 7) //查询数据: type Result struct { Name string Age int } var result []Result db.Raw("SELECT name,age FROM shop_user WHERE id=? ", 8).Scan(&result) db.Raw("SELECT name,age FROM shop_user WHERE id IN ? ", []int{5, 6, 8}).Scan(&result) var age int //查询单个字段 db.Raw("SELECT age FROM shop_user WHERE id=? ", 6).Scan(&age) fmt.Println(result)
GORM DryRun模式
生成 SQL 但不执行。 它可以用于准备或测试生成的 SQL
dsn := “root:123456@tcp(127.0.0.1:3306)/shop?charset=utf8mb4&parseTime=True&loc=Local” db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{ NamingStrategy: schema.NamingStrategy{ Table: true, TablePrefix: “shop_”, }, DryRun: true, //全局打开 sql语句不会执行 }) user := User{Name: "lampol", Age: 23, Email: "123@qq.com", Sex: 1} stmt := db.Create(&user).Statement fmt.Println(db.Dialector.Explain(stmt.SQL.String(), stmt.Vars...))
不在全局生效的DryRun模式:
var user User res := db.Session(&gorm.Session{DryRun: true}).First(&user).Statement.SQL.String() fmt.Println(res)
gorm钩子
Hook 是在创建、查询、更新、删除等操作之前、之后调用的函数
钩子方法的函数签名应该是 func(*gorm.DB) error
插入 BeforeSave BeforeCreate AfterCreate AfterSave
更新 BeforeSave BeforeUpdate AfterUpdate AfterSave
删除 BeforeDelete AfterDelete
查询 AfterFind
钩子代码示例1:
// 定义钩子 func (u *User) BeforeSave(tx *gorm.DB) (err error) { fmt.Println("BeforeSave....") return } func (u *User) BeforeCreate(tx *gorm.DB) (err error) { fmt.Println("BeforeCreate....") return } func (u *User) AfterSave(tx *gorm.DB) (err error) { fmt.Println("AfterSave....") return } func (u *User) AfterCreate(tx *gorm.DB) (err error) { fmt.Println("AfterCreate....") return } func main() { user := User{Name: "lampol33", Age: 33, Email: "32423@qq.com"} db.Create(&user) fmt.Println("create ....") //更新 db.Model(&User{}).Where("id=?", 11).Update("name", "lampol_9") fmt.Println("update ....") //使用 table,未使用Model,无法使用钩子 //db.Table("shop_user").Where("id=?", 11).Update("name", "lampol_9")}
打印结果:
GORM 事务
数据表引擎需要 innodb类型才可以使用事务
show create table shop_user;
alter table shop_user engine="innodb";
// 开始事务 tx := db.Begin() // 遇到错误时回滚事务 tx.Rollback() // 提交事务 tx.Commit()
事务示例1:
tx := db.Begin() user := User{Name: "lampol44", Age: 44, Email: "asdfasdf@qq.com"} delnum := tx.Delete(&User{}, 100).RowsAffected insNum := tx.Create(&user).RowsAffected fmt.Println(delnum, insNum) if delnum != 1 || insNum != 1 { //失败 回滚 fmt.Println("rollback ....") tx.Rollback() return } //未失败,提交 tx.Commit() fmt.Println("commit ....")
完结
但行好事,莫问前程!
本文来自博客园,作者:yangphp,转载请注明原文链接:https://www.cnblogs.com/ypeih/p/17320080.html