Go语言学习(十一)--gorm

一、概述

1.1、ORM简介

对象关系映射模式(ORM)是一种为了解决面向对象与关系数据库(如mysql数据库)存在的互不匹配的现象的技术。简单来说,ORM十通过使用描述对象和数据库之间映射的元数据,将程序中的对象自动持久化到关系数据库中。

1.2、安装

在goland中引入,然后安装就可以啦

"gorm.io/driver/mysql"
"gorm.io/gorm"

1.3、相关操作

1.3.1、创建一个结构体---整个过程的前提

注意gorm.Model

type Product struct {
	gorm.Model //属性:ID、CreateTime、UpdateTime、DeleteTime
	Code       string
	Price      uint
}

1.3.2、建立连接

dsn := "root:123456@tcp(127.0.0.1:3306)/go_study?charset=utf8mb4&parseTime=True&loc=Local"
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		log.Fatal(err)
	}

1.3.3、 创建表

db.AutoMigrate(&Product{})
func create(db *gorm.DB) {
	//创建表  把结构体创建表直接到数据库里面
	db.AutoMigrate(&Product{}) //表的名称为products
}

1.3.4、插入数据

db.Create(&p)
// 插入数据-插入一整行
func insert(db *gorm.DB) {
	p := Product{
		Code:  "Q1002",
		Price: 30,
	}
	result := db.Create(&p)
	fmt.Printf("影响的行数:%v\n", result.RowsAffected)
	fmt.Printf("p.id:%v\n", p.ID)
	/*
		影响的行数:1
		p.id:3
	*/
}

// 插入数据--只插入某些列
func insert2(db *gorm.DB) {
	p := Product{
		Code:  "Q1003",
		Price: 60,
	}
	result := db.Select("Code", "CreatedAt").Create(&p)
	//只往Code和CreatedAt列中插入了信息
	fmt.Printf("影响的行数:%v\n", result.RowsAffected)
	fmt.Printf("p.id:%v\n", p.ID)
	/*
		影响的行数:1
		p.id:4
	*/
}

// 插入数据--批量插入
func insert3(db *gorm.DB) {
	var p = []Product{{Code: "Q1004"}, {Code: "Q1005"}, {Code: "Q1006"}}
	db.Create(&p)
}

1.3.5、查询

  • db.First(&product, 1)
  • db.First(&product, "code=?", "1001")
// 查询
func find1(db *gorm.DB) {
	var product Product
	//获取第一条记录--主键升序
	db.First(&product)
	fmt.Printf("product.id:%v\n", product.ID)
	//获取第一条记录--无指定顺序
	db.Take(&product)
	fmt.Printf("product.id:%v\n", product.ID)
	//获取最后一条记录
	db.Last(&product)
	fmt.Printf("product.id:%v\n", product.ID)

	//根据条件来查询
	db.First(&product, "code=?", "1001")
	fmt.Printf("find result:%v\n", product)
}

// 根据主键检索
func find2(db *gorm.DB) {
	var product Product
	//根据主键查询
	db.First(&product, 3) //&product是指将查询到的结果放在product中。1是指查询主键为1的值
	fmt.Printf("find result ID:%v\n", product.ID)
	//根据主键批量查询
	var products []Product
	db.Find(&products, []int{1, 2, 3})
	for _, p := range products {
		fmt.Printf("find result ID:%v\n", p.ID)
	}
}

// 检索全部对象
func find3(db *gorm.DB) {
	var products []Product
	result := db.Find(&products)
	fmt.Printf("查了%v行\n", result.RowsAffected)
}

条件查询

更多查看gorm查询记录 

1.3.6、更新

  • db.Model(&product).Update("Price", 200)
  • db.Model(&product).Updates(Product{Price: 300, Code: "F003"})
  • db.Model(&product).Updates(map[string]interface{}{"Price": 200, "Code": "F003"})
func update(db *gorm.DB) {
	//更新之前首先要先查询,查出来。可以根据主键或者条件来查询
	var product Product
	db.First(&product, 1)
	//查出来之后,将价格改成200
	db.Model(&product).Update("Price", 200)
	//更新多个属性的数据
	//db.Model(&product).Updates(Product{Price: 300, Code: "F003"})
	db.Model(&product).Updates(map[string]interface{}{"Price": 200, "Code": "F003"})
}

gorm更新

1.3.7、 删除

db.Delete(&product, 2)
不是物理删除,是软删除,是添加了一个删除标记。在deleteTime字段
// 删除 --不是物理删除,是软删除,是添加了一个删除标记。再deleteTime字段
func del(db *gorm.DB) {
	var product Product
	db.First(&product, 2) //删除之前先找到
	db.Delete(&product, 2)
}

gorm删除

示例代码

package main

import (
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"log"
)

type Product struct {
	gorm.Model //属性:ID、CreateTime、UpdateTime、DeleteTime
	Code       string
	Price      uint
}

// 创建表
func create(db *gorm.DB) {
	//创建表  把结构体创建表直接到数据库里面
	db.AutoMigrate(&Product{}) //表的名称为products
}

// 插入数据
func insert(db *gorm.DB) {
	p := Product{
		Code:  "1002",
		Price: 1000,
	}
	db.Create(&p)
}

// 查询
func find(db *gorm.DB) {
	var product Product
	//根据主键查询
	db.First(&product, 1) //&product是指将查询到的结果放在product中。1是指查询主键为1的值
	fmt.Printf("find result:%v\n", product)
	//根据条件来查询
	db.First(&product, "code=?", "1001")
	fmt.Printf("find result:%v\n", product)
}

// 更新
func update(db *gorm.DB) {
	//更新之前首先要先查询,查出来。可以根据主键或者条件来查询
	var product Product
	db.First(&product, 1)
	//查出来之后,将价格改成200
	db.Model(&product).Update("Price", 200)
	//更新多个属性的数据
	//db.Model(&product).Updates(Product{Price: 300, Code: "F003"})
	db.Model(&product).Updates(map[string]interface{}{"Price": 200, "Code": "F003"})
}

// 删除 --不是物理删除,是软删除,是添加了一个删除标记。再deleteTime字段
func del(db *gorm.DB) {
	var product Product
	db.First(&product, 2) //删除之前先找到
	db.Delete(&product, 2)
}
func main() {
	dsn := "root:123456@tcp(127.0.0.1:3306)/go_study?charset=utf8mb4&parseTime=True&loc=Local"
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		log.Fatal(err)
	}
	//find(db)
	//update(db)
	del(db)
}

二、gorm声明模型

type Product struct {
	gorm.Model //属性:ID、CreateTime、UpdateTime、DeleteTime
	Code       string
	Price      uint
}

 Grom更倾向于约定,而不是配置

 gorm.Model定义

1.4、原生SQL和SQL构造器

func testRow1() {
	type Result struct {
		ID   int
		Name string
		Age  int
	}
	var result Result
	//注意要指定运行结果的存放结构,例如这里的result和下面的age
	db.Raw("select id,name,age from users where name=?", "tom").Scan(&result)
	fmt.Printf("result:%v\n", result) //result:{1 tom 11}
	var age int
	db.Raw("select sum(age) from users").Scan(&age) //age:23  把找到的东西放在age里面
	fmt.Printf("age:%v\n", age)
}

func testRaw2() {
	db.Exec("update users set age=? where name=?", 100, "tom") //执行一个更新
}

// 命名参数
func testRaw3() {
	var user User
	db.Where("name=@myname", sql.Named("myname", "tom")).Find(&user)
	fmt.Printf("%v\n", user)
}

func testRaw4() {
	var name string
	var age int
	row := db.Table("users").Where("name=?", "tom").Select("name", "age").Row()
	row.Scan(&name, &age)
	fmt.Printf("name:%v\n", name)
	fmt.Printf("age:%v\n", age)

	rows, _ := db.Model(&User{}).Where("age>?", 18).Select("name", "age").Rows()
	for rows.Next() {
		rows.Scan(&name, &age)
		fmt.Printf("name:%v\n", name)
		fmt.Printf("age:%v\n", age)
	}
}

 1.5、关联关系

1.5.1、Belongs To

gorm关联关系Belongs To(属于)

多对一关系


type Email struct {
	gorm.Model
	Email     string
	UserNewID uint
}
type Language struct {
	gorm.Model
	Name    string
	UserNew []*UserNew `gorm:"many2many:user_news_languages"`
}
type Address struct {
	gorm.Model
	Address1  string
	UserNewID uint
}
type UserNew struct {
	gorm.Model
	Name            string
	BillingAddress  Address
	ShippingAddress Address
	Emails          []Email
	Languages       []Language `gorm:"many2many:user_news_languages"`
}

func create() {
	db.AutoMigrate(&UserNew{}, &Email{}, &Address{}, &Language{})
}
func test1() {
	user := UserNew{
		Name:            "jinzhu",
		BillingAddress:  Address{Address1: "Billing Address - Address 1"},
		ShippingAddress: Address{Address1: "Shipping Address - Address 1"},
		Emails: []Email{
			{Email: "jinzhu@example.com"},
			{Email: "jinzhu-2@example.com"},
		},
		Languages: []Language{
			{Name: "ZH"},
			{Name: "EN"},
		},
	}
	//db.Create(&user)
	//如果使用的不是create,而是update,就要用下面这句话
	db.Session(&gorm.Session{FullSaveAssociations: true}).Updates(&user)
}

// 关联的查询
func test2() {
	var user UserNew
	//First拿到第一个用户
	db.First(&user)
	var lan []Language
	db.Model(&user).Association("Languages").Find(&lan)
	fmt.Printf("languages:%v\n", lan)
}

// 关联计数
func test3() {
	var user UserNew
	//First拿到第一个用户
	db.First(&user)
	count := db.Model(&user).Association("Languages").Count()
	fmt.Printf("Count:%v\n", count)
}

1.5.2、has one

gorm关联关系之Has One(有一个)

has one 与另一个模型建立一对一的关联,但是它和一对一关系有些许不同。这种关联表明一个模型的每个实例都包含或拥有另一个模型的一个实例

// has to关系,一对一  一个卡片只能有一个主人
func test1() {
	type CreditCard struct {
		gorm.Model
		Number    string
		UserNewID uint //注意这里一定是UserNewID,如果是别的,或者写错成User,就不会创建成功
		//UserNewID是外键,对应UserNew中的ID
	}
	type UserNew struct {
		gorm.Model
		CreditCard CreditCard
	}
	db.AutoMigrate(&UserNew{}, &CreditCard{}) //注意创建关系,分前后
}

多态关联

Gorm为has one和has many提供了多态关联支持,它将拥有者实体的表明、主键值都保存到多态类型的字段中

// has to关系,一对一  一个卡片只能有一个主人
func test1() {
	type CreditCard struct {
		gorm.Model
		Number    string
		UserNewID uint //注意这里一定是UserNewID,如果是别的,或者写错成User,就不会创建成功
		//UserNewID是外键,对应UserNew中的ID
	}
	type UserNew struct {
		gorm.Model
		CreditCard CreditCard
	}
	db.AutoMigrate(&UserNew{}, &CreditCard{}) //注意创建关系,分前后
}

// 多态关联
func test2() {
	db.AutoMigrate(&Toy{}, &Cat{}, &Dog{})
}
func test3() {
	db.Create(&Dog{Name: "dog1", Toy: Toy{Name: "toy1"}})
	db.Create(&Cat{Name: "cat1", Toy: Toy{Name: "toy2"}})
}

最后的结果:

在向toy中添加时,也会自动添加到dog表和cat表中

1.5.3、has many

https://mp.weixin.qq.com/s/i5R_WKpPkak0F8jcg3jnfw

has many与另一个模型建立了一对多的连接。不同于has one,拥有者可以有零或者多个关联模型

例如,每个user可以有多张credit card

type Language struct {
	gorm.Model
	Name string
}
type UserNew struct {
	gorm.Model
	Languages []Language `gorm:"many2many:user_new_languages"`
}

func test1() {
	db.AutoMigrate(&Language{}, &UserNew{})
	//最后创建了三张表,分别是language、usernew、user_new_languages(中间表--userid、languagesid)
	//当我们添加记录时,会自动往中间表中添加
}
func insert() {
	l := Language{
		Name: "English",
	}
	l2 := Language{
		Name: "chinese",
	}
	//创建用户时要指定语言
	user := &UserNew{
		Languages: []Language{l, l2},
	}
	db.Create(&user)
	db.Create(&l)
}

数据库:

1.5.3、多对多 many to many

gorm关联关系之Many To Many

many to many会在两个model中添加一张连接表

例如,应用里面包含了user和language,且一个user可以说多种language,多个user也可以说一种language

type Language struct {
	gorm.Model
	Name string
}
type UserNew struct {
	gorm.Model
	Languages []Language `gorm:"many2many:user_new_languages"`
}

func test1() {
	db.AutoMigrate(&Language{}, &UserNew{})
	//最后创建了三张表,分别是language、usernew、user_new_languages(中间表--userid、languagesid)
	//当我们添加记录时,会自动往中间表中添加
}
func insert() {
	l := Language{
		Name: "English",
	}
	l2 := Language{
		Name: "chinese",
	}
	//创建用户时要指定语言
	user := &UserNew{
		Languages: []Language{l, l2},
	}
	db.Create(&user)
	db.Create(&l)
}

数据库结果; 

 

 1.5.4、实体关联

gorm关联关系之实体关联

type Email struct {
	gorm.Model
	Email     string
	UserNewID uint
}
type Language struct {
	gorm.Model
	Name    string
	UserNew []*UserNew `gorm:"many2many:user_news_languages"`
}
type Address struct {
	gorm.Model
	Address1  string
	UserNewID uint
}
type UserNew struct {
	gorm.Model
	Name            string
	BillingAddress  Address
	ShippingAddress Address
	Emails          []Email
	Languages       []Language `gorm:"many2many:user_news_languages"`
}

func create() {
	db.AutoMigrate(&UserNew{}, &Email{}, &Address{}, &Language{})
}
func test1() {
	user := UserNew{
		Name:            "jinzhu",
		BillingAddress:  Address{Address1: "Billing Address - Address 1"},
		ShippingAddress: Address{Address1: "Shipping Address - Address 1"},
		Emails: []Email{
			{Email: "jinzhu@example.com"},
			{Email: "jinzhu-2@example.com"},
		},
		Languages: []Language{
			{Name: "ZH"},
			{Name: "EN"},
		},
	}
	//db.Create(&user)
	//如果使用的不是create,而是update,就要用下面这句话
	db.Session(&gorm.Session{FullSaveAssociations: true}).Updates(&user)
}

更新后数据库的表现:

可见,虽然只更新了usernew,但是与之关联的表全都发生了改变 

1.6、gorm会话--session

gorm 会话

1.7、gorm事务

确保数据的一致性。Gorm在事务里面执行写入操作。要么都成功、要么都失败

gorm 事务

package main

import (
	_ "github.com/go-sql-driver/mysql"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"log"
)

var db *gorm.DB

func test1() {
	//session级别的禁用事务
	db.Session(&gorm.Session{SkipDefaultTransaction: true})
}

type User struct {
	gorm.Model
	Name string
}

// c测试事务操作--没有使用事务控制,所以user会添加成功。nil添加失败
func test2() {
	user := User{
		Name: "tom",
	}
	db.Create(&user)
	db.Create(nil) //肯定失败
}

// 测试事务操作---使用事务控制,都没有添加成功--手动控制
func test3() {
	user := User{
		Name: "kite",
	}
	//手动控制
	tx := db.Begin() //有事务控制的db
	tx.Create(&user)
	err := tx.Create(nil).Error
	if err != nil {
		tx.Rollback()
	} else {
		tx.Commit()
	}
}

func test4() {
	user := User{
		Name: "tony",
	}
	//自动完成Rollback或者commit
	db.Transaction(func(tx *gorm.DB) error {
		if err := tx.Create(&user).Error; err != nil {
			return err
		}
		if err := tx.Create(nil).Error; err != nil {
			return err
		}
		return nil
	})
}

func main() {
	dsn := "root:123456@tcp(127.0.0.1:3306)/go_study?charset=utf8mb4&parseTime=True&loc=Local"
	//SkipDefaultTransaction: true 禁用全局事务。这样事务就不生效了
	d, err := gorm.Open(mysql.Open(dsn), &gorm.Config{ /*SkipDefaultTransaction: true*/ })
	if err != nil {
		log.Fatal(err)
	}
	db = d
	//test2()
	//test3()
	test4()

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值