数据库操作(mysql,gorm实现基本的增删改查)

连接

//连接数据库
dsn := "root:password@tcp(localhost)/sql_test?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
//错误判断
if err != nil {
	panic(err)
}
//创建一个表表名叫UserTest,进入数据库中后名字为user_tests
db.AutoMigrate(&UserTest{})
MySQl 驱动程序提供了 一些高级配置 可以在初始化过程中使用
db, err := gorm.Open(mysql.New(mysql.Config{
  DSN: "gorm:gorm@tcp(127.0.0.1:3306)/gorm?charset=utf8&parseTime=True&loc=Local", // DSN data source name
  DefaultStringSize: 256, // string 类型字段的默认长度
  DisableDatetimePrecision: true, // 禁用 datetime 精度,MySQL 5.6 之前的数据库不支持
  DontSupportRenameIndex: true, // 重命名索引时采用删除并新建的方式,MySQL 5.7 之前的数据库和 MariaDB 不支持重命名索引
  DontSupportRenameColumn: true, // 用 `change` 重命名列,MySQL 8 之前的数据库和 MariaDB 不支持重命名列
  SkipInitializeWithVersion: false, // 根据当前 MySQL 版本自动配置
}), &gorm.Config{})

创建

type UserTest struct {
	gorm.Model
	Name     string
	Birthday time.Time
}

func main4() {
	//连接数据库
	dsn := "root:password@tcp(localhost)/sql_test?charset=utf8mb4&parseTime=True&loc=Local"
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	//错误判断
	if err != nil {
		panic(err)
	}
	//创建一个表表名叫UserTest,进入数据库中后名字为user_tests
	db.AutoMigrate(&UserTest{})
	//创建记录
	user := UserTest{Name: "zxp", Birthday: time.Now()}
	db.Create(&user)
用指定的字段创建记录
  • 创建记录并更新给出的字段。
//创建记录
user1 := UserTest{Name: "张三", Birthday: time.Now()}
//用指定的字段创建记录,比如只插入Name和CreatedAt
db.Select("Name", "CreatedAt").Create(&user1)*/
  • 创建一个记录且一同忽略传递给略去的字段值。
//创建一个记录且一同忽略传递略去的字段值
//比如Name不会传值
user1 := UserTest{Name: "李四", Birthday: time.Now()}
db.Omit("Name").Create(&user1)
批量插入
var users = []UserTest{
		{Name: "王五"},
		{Name: "小红"},
		{Name: "小明"},
	}
db.Create(&users)
CreateInBatches
//创建记录
var users = []User{{name: "jinzhu_1"}, ...., {Name: "jinzhu_10000"}}

// 数量为 100
db.CreateInBatches(users, 100)
根据Map创建
//根据map创建
	db.Model(&UserTest{}).Create(map[string]interface{}{
		"Name":     "张三",
		"Birthday": time.Now(),
	})
//根据map切片创建
	db.Model(&UserTest{}).Create([]map[string]interface{}{
		{"Name": "我", "Birthday": time.Now(), "CreatedAt": time.Now()},
		{"Name": "爱", "Birthday": time.Now(), "CreatedAt": time.Now()},
		{"Name": "你", "Birthday": time.Now(), "CreatedAt": time.Now()},
	})

查询

// 获取第一条记录(主键升序)
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)


测试:

import (
	"fmt"

	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)
func main(){
    //连接数据库
	dsn := "root:zxp990926@tcp(localhost)/sql_test?charset=utf8mb4&parseTime=True&loc=Local"
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	//错误判断
	if err != nil {
		panic(err)
	}
    //实例化结构体,也就是对应要查询的表的结构体
	var b UserTest
	//查询第一条记录
	/*db.First(&b)
	fmt.Printf("%v\n", b)
	fmt.Println("==========================")
	*/

	/*// 获取一条记录,没有指定排序字段
	db.Last(&b)
	fmt.Printf("%v\n", b)
	fmt.Println("==========================")*/

	/*result := db.First(&b)
	affected := result.RowsAffected //返回找到的记录数
	fmt.Println(affected)
	fmt.Println("==========================")*/

	/*//查询指定人的部分信息
	db.Find(&b, "Name=?", "我")
	fmt.Println(b.ID)
	fmt.Println("==========================")*/

	// 检查 ErrRecordNotFound 错误
	//errors.Is(result.Error, gorm.ErrRecordNotFound)

	//用主键检索
	db.First(&b, "2")
	fmt.Println(b)
	fmt.Println("==========================")
}

注意first和last
FirstLastdb.Model()
var user User
var users []User  

// 有效,因为目标 struct 是指针
db.First(&user)
// SELECT * FROM `users` ORDER BY `users`.`id` LIMIT 1

// 有效,因为通过 `db.Model()` 指定了 model
result := map[string]interface{}{}
db.Model(&User{}).First(&result)
// SELECT * FROM `users` ORDER BY `users`.`id` LIMIT 1

// 无效
result := map[string]interface{}{}
db.Table("users").First(&result)

// 配合 Take 有效
result := map[string]interface{}{}
db.Table("users").Take(&result)

// 未指定主键,会根据第一个字段排序(即:`Code`)
type Language struct {
  Code string
  Name string
}
db.First(&Language{})
// SELECT * FROM `languages` ORDER BY `languages`.`code` LIMIT 1

查询所有对象

//检索所有对象
var users []UserTest
result := db.Find(&users)
fmt.Println(users)
affected := result.RowsAffected
fmt.Println(affected) //7
where查询
// 获取第一条匹配的记录
db.Where("name = ?", "jinzhu").First(&user)
// SELECT * FROM users WHERE name = 'jinzhu' ORDER BY id LIMIT 1;

// 获取全部匹配的记录
db.Where("name <> ?", "jinzhu").Find(&users)
// SELECT * FROM users WHERE name <> 'jinzhu';

// IN
db.Where("name IN ?", []string{"jinzhu", "jinzhu 2"}).Find(&users)
// SELECT * FROM users WHERE name IN ('jinzhu','jinzhu 2');

// LIKE
db.Where("name LIKE ?", "%jin%").Find(&users)
// SELECT * FROM users WHERE name LIKE '%jin%';

// AND
db.Where("name = ? AND age >= ?", "jinzhu", "22").Find(&users)
// SELECT * FROM users WHERE name = 'jinzhu' AND age >= 22;

// Time
db.Where("updated_at > ?", lastWeek).Find(&users)
// SELECT * FROM users WHERE updated_at > '2000-01-01 00:00:00';

// BETWEEN
db.Where("created_at BETWEEN ? AND ?", lastWeek, today).Find(&users)
// SELECT * FROM users WHERE created_at BETWEEN '2000-01-01 00:00:00' AND '2000-01-08 00:00:00';

测试

package main

import (
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

func main() {
	dsn := "root:zxp990926@tcp(localhost)/sql_test?charset=utf8mb4&parseTime=True&loc=Local"
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	//错误判断
	if err != nil {
		panic(err)
	}
	//var b UserTest

	/*//获取第一条匹配的记录
	db.Where("name = ?", "我").Find(&b)
	fmt.Println(b)
	fmt.Println("=========================================")*/

	获取全部匹配的记录
	//var users []UserTest
	//db.Where("Name <> ?", "爱").Find(&users)
	//fmt.Println(users)
	//fmt.Println("=========================================")

	/*//根据名字获得对应的记录
	var users []UserTest
	db.Where("Name IN ?", []string{"我", "爱"}).Find(&users)
	fmt.Println(users)*/

	/*var users []UserTest
	//有数据库可知能查到小明和小红
	db.Where("Name LIKE ?", "%小%").Find(&users)
	fmt.Println(users)*/

	/*//查询名字叫小红并且生日大于等于0000-00-00 00:00:00.000
	var users []UserTest
	db.Where("Name = ? AND Birthday >= ?", "小红", "0000-00-00 00:00:00.000").Find(&users)
	fmt.Println(users)*/

	/*//时间比
	var users []UserTest
	lastweek := time.Now()
	db.Where("updated_at > ?", lastweek).Find(&users)
	fmt.Println(users)*/

}

Struct & Map 条件的where查询
// Struct
db.Where(&User{Name: "jinzhu", Age: 20}).First(&user)
// SELECT * FROM users WHERE name = "jinzhu" AND age = 20 ORDER BY id LIMIT 1;

// Map
db.Where(map[string]interface{}{"name": "jinzhu", "age": 20}).Find(&users)
// SELECT * FROM users WHERE name = "jinzhu" AND age = 20;

// 主键切片条件
db.Where([]int64{20, 21, 22}).Find(&users)
// SELECT * FROM users WHERE id IN (20, 21, 22);
db.Where(&User{Name: "jinzhu", Age: 0}).Find(&users)// SELECT * FROM users WHERE name = "jinzhu";
内联条件
// 根据主键获取记录,如果是非整型主键
db.First(&user, "id = ?", "string_primary_key")
// SELECT * FROM users WHERE id = 'string_primary_key';

// Plain SQL
db.Find(&user, "name = ?", "jinzhu")
// SELECT * FROM users WHERE name = "jinzhu";

db.Find(&users, "name <> ? AND age > ?", "jinzhu", 20)
// SELECT * FROM users WHERE name <> "jinzhu" AND age > 20;

// Struct
db.Find(&users, User{Age: 20})
// SELECT * FROM users WHERE age = 20;

// Map
db.Find(&users, map[string]interface{}{"age": 20})
// SELECT * FROM users WHERE age = 20;
Not条件
db.Not("name = ?", "jinzhu").First(&user)
// SELECT * FROM users WHERE NOT name = "jinzhu" ORDER BY id LIMIT 1;
测试:
//Not条件
//实例化结构体
var user1 UserTest
db.Not("Name = ?", "王五").First(&user1)
fmt.Println(user1)
查询结果为第二行的小红,如果填写的名字不是王五则查询的结果为王五


// Not In
db.Not(map[string]interface{}{"name": []string{"jinzhu", "jinzhu 2"}}).Find(&users)
// SELECT * FROM users WHERE name NOT IN ("jinzhu", "jinzhu 2");
测试:
var users []UserTest
db.Not(map[string]interface{}{"Name": []string{"王五", "爱"}}).Find(&users)
fmt.Printf("%v\n", users)
查询结果为除去王五和爱的所有人


// 不在主键切片中的记录
db.Not([]int64{1,2,3}).First(&user)
// SELECT * FROM users WHERE id NOT IN (1,2,3) ORDER BY id LIMIT 1;
测试
var user1 UserTest
db.Not([]int64{1, 2, 3}).First(&user1)
fmt.Println(user1)
查询结果为id = 4的张三
or条件
db.Where("role = ?", "admin").Or("role = ?", "super_admin").Find(&users)
// SELECT * FROM users WHERE role = 'admin' OR role = 'super_admin';

// Struct
db.Where("name = 'jinzhu'").Or(User{Name: "jinzhu 2", Age: 18}).Find(&users)
// SELECT * FROM users WHERE name = 'jinzhu' OR (name = 'jinzhu 2' AND age = 18);

// Map
db.Where("name = 'jinzhu'").Or(map[string]interface{}{"name": "jinzhu 2", "age": 18}).Find(&users)
// SELECT * FROM users WHERE name = 'jinzhu' OR (name = 'jinzhu 2' AND age = 18);

测试:

var users []UserTest
db.Where("Name = ?", "张三").Or("Name = ?", "爱").Find(&users)
fmt.Println(users)
//查询结果为张三和爱的记录


选择特定字段
db.Select("name", "age").Find(&users)
// SELECT name, age FROM users;

db.Select([]string{"name", "age"}).Find(&users)
// SELECT name, age FROM users;

db.Table("users").Select("COALESCE(age,?)", 42).Rows()
// SELECT COALESCE(age,'42') FROM users;

测试:

var users1 []UserInfo
db.Select("Name", "Hobby").Find(&users1)
fmt.Println(&users1)
查询结果为:[{0 张三  学习} {0 李四  玩} {0 zxp  hahaha}]
Order
db.Order("age desc, name").Find(&users)
// SELECT * FROM users ORDER BY age desc, name;

// 多个 order
db.Order("age desc").Order("name").Find(&users)
// SELECT * FROM users ORDER BY age desc, name;

db.Clauses(clause.OrderBy{
  Expression: clause.Expr{SQL: "FIELD(id,?)", Vars: []interface{}{[]int{1, 2, 3}}, WithoutParentheses: true},
}).Find(&User{})
// SELECT * FROM users ORDER BY FIELD(id,1,2,3)

测试:

var users1 []UserInfo
db.Order("ID desc,Name ").Find(&users1)//升序用asc,降序用desc
fmt.Println(users1)
//根据ID进行降序排列
输出结果为:[{3 zxp 男 hahaha} {2 李四 男 玩} {1 张三 男 学习}]

var users1 []UserInfo
db.Order("ID desc").Order("Hobby").Find(&users1)
fmt.Println(users1)
输出结果为:[{3 zxp 男 hahaha} {2 李四 男 玩} {1 张三 男 学习}]

//自定义排序
//FIELD()函数是将参数1的字段对后续参数进行比较,并返回1、2、3等等,如果遇到null或者没有在结果集上存在的数据,则返回0,然后根据升序进行排序。
	var users1 []UserInfo
	db.Clauses(clause.OrderBy{
		Expression: clause.Expr{SQL: "FIELD(id,?)", Vars: []interface{}{[]int{1, 3, 2}}, WithoutParentheses: true},
	}).Find(&users1)
	fmt.Println(users1)
输出结果为:[{1 张三 男 学习} {3 zxp 男 hahaha} {2 李四 男 玩}]

Limit &Offset
LimitOffset
db.Limit(3).Find(&users)
// SELECT * FROM users LIMIT 3;

// 通过 -1 消除 Limit 条件
db.Limit(10).Find(&users1).Limit(-1).Find(&users2)
// SELECT * FROM users LIMIT 10; (users1)
// SELECT * FROM users; (users2)

db.Offset(3).Find(&users)
// SELECT * FROM users OFFSET 3;

db.Limit(10).Offset(5).Find(&users)
// SELECT * FROM users OFFSET 5 LIMIT 10;

// 通过 -1 消除 Offset 条件
db.Offset(10).Find(&users1).Offset(-1).Find(&users2)
// SELECT * FROM users OFFSET 10; (users1)
// SELECT * FROM users; (users2)

测试:

result := db.Limit(2).Find(&users1)
affected := result.RowsAffected
fmt.Println(users1)
fmt.Println(affected)
输出结果为:[{1 张三 男 学习} {2 李四 男 玩}]
		  2

// 通过 -1 消除 Limit 条件
result := db.Limit(2).Find(&users1).Limit(-1).Find(&users1)
affected := result.RowsAffected
fmt.Println(users1)
fmt.Println(affected)
输出结果为:[{1 张三 男 学习} {2 李四 男 玩} {3 zxp 男 hahaha}]
3

Distinct(去重复)
db.Distinct("name", "age").Order("name, age desc").Find(&results)
 //SELECT DISTINCT `name`,`age` FROM `results` ORDER BY Name,Age desc
joins(多表连接)
type result struct {
  Name  string
  Email string
}

db.Model(&User{}).Select("users.name, emails.email").Joins("left join emails on emails.user_id = users.id").Scan(&result{})
// SELECT users.name, emails.email FROM `users` left join emails on emails.user_id = users.id

rows, err := db.Table("users").Select("users.name, emails.email").Joins("left join emails on emails.user_id = users.id").Rows()
for rows.Next() {
  ...
}

db.Table("users").Select("users.name, emails.email").Joins("left join emails on emails.user_id = users.id").Scan(&results)

// 带参数的多表连接
db.Joins("JOIN emails ON emails.user_id = users.id AND emails.email = ?", "jinzhu@example.org").Joins("JOIN credit_cards ON credit_
Scan
import (
	"fmt"

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

type Result struct {
	Name string
	Age  int
}

func main9() {
	//连接数据库
	dsn := "root:zxp990926@tcp(localhost)/sql_test?charset=utf8mb4&parseTime=True&loc=Local"
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	//错误判断
	if err != nil {
		panic(err)
	}
	//scan
	var rets Result
	db.Table("user1").Select("Name", "Age").Where("Name = ?", "stu4").Scan(&rets)
	fmt.Println(rets)//{stu4 19}
	fmt.Println("======================")

	var rets1 Result
	db.Raw("select Name,Age from user1 where Name = ?", "stu3").Scan(&rets1)
	fmt.Println(rets1)//{stu3 19}   

}

高级查询(略)

type User1 struct {
	ID        uint `gorm:"primaryKey"`
	Name      string
	Age       int
	CreatedAt time.Time
	UpdateAt  time.Time
}
type Result struct {
	Name string
	Age  int
}

var rest2 []Result
db.Model(&User1{}).Select("Name", "Age").Where("Age > ?", 18).Limit(3).Find(&rest2)
fmt.Println(rest2)
查询结果为:[{stu2 20} {stu3 19} {stu4 19}]

更新

保存所有字段
Save
//实例化一个表的结构体
var user User1
db.First(&user)
user.Age = 30
db.Save(&user)//age = 30
更新单个列
UpdateErrMissingWhereClauseModel
//更新单个列
db.Model(&User1{}).Where("Age = ?", 19).Update("Name", "love you")

更新多列
Updatesstructmap[string]interface{}struct
//更新多列
db.Model(&User1{}).Where("Name = ?", "love you").Updates(map[string]interface{}{
	"Name": "zxp", "Age": 20,
})
db.Table("user1").Where("id IN ?", []int{3, 4, 6}).Updates(map[string]interface{}{
		"Name": "zxp",
})
Selectmap
更新选定字段
//更新选定字段(只更新了name)
db.Model(&User1{}).Select("Name").Where("Name = ?", "zxp").Updates(map[string]interface{}{
		"Name": "love you",
		"Age":  100,
})

//(只更新了未选中的age)
db.Model(&User1{}).Omit("Name").Where("Name = ?", "love you").Updates(User1{
	Name: "zcp",
	Age:  20,
})
阻止全局更新
db.Model(&User{}).Update("name", "jinzhu").Error // gorm.ErrMissingWhereClause
//实现多更新
//age的年龄都将是18
db.Session(&gorm.Session{AllowGlobalUpdate: true}).Model(&User1{}).Update("Age", 18)

db.Model(&User{}).Where("1 = 1").Update("name", "zxp")
// UPDATE users SET `name` = "jinzhu" WHERE 1=1
更新的记录数
result := db.Model(&User1{}).Select("Name", "Age").Where("Name = ?", "zxp").Updates(map[string]interface{}{
		"Name": "love you",
		"Age":  20,
	})
fmt.Println(result.RowsAffected)
使用sql表达式更新
db.Model(&product).Where("quantity > 1").UpdateColumn("quantity", gorm.Expr("quantity - ?", 1))
// UPDATE "products" SET "quantity" = quantity - 1 WHERE "id" = 3 AND quantity > 1;
根据子查询进行更新
db.Model(&user).Update("company_name", db.Model(&Company{}).Select("name").Where("companies.id = users.company_id"))
// UPDATE "users" SET "company_name" = (SELECT name FROM companies WHERE companies.id = users.company_id);

db.Table("users as u").Where("name = ?", "jinzhu").Update("company_name", db.Table("companies as c").Select("name").Where("c.id = u.company_id"))

db.Table("users as u").Where("name = ?", "jinzhu").Updates(map[string]interface{}{}{"company_name": db.Table("companies as c").Select("name").Where
返回修改行的数据
// 返回所有列
var users []User
DB.Model(&users).Clauses(clause.Returning{}).Where("role = ?", "admin").Update("salary", gorm.Expr("salary * ?", 2))
// UPDATE `users` SET `salary`=salary * 2,`updated_at`="2021-10-28 17:37:23.19" WHERE role = "admin" RETURNING *
// users => []User{{ID: 1, Name: "jinzhu", Role: "admin", Salary: 100}, {ID: 2, Name: "jinzhu.2", Role: "admin", Salary: 1000}}


// 返回指定的列
DB.Model(&users).Clauses(clause.Returning{Columns: []clause.Column{{Name: "name"}, {Name: "salary"}}}).Where("role = ?", "admin").Update("salary", gorm.Expr("salary * ?", 2))
// UPDATE `users` SET `salary`=salary * 2,`updated_at`="2021-10-28 17:37:23.19" WHERE role = "admin" RETURNING `name`, `salary`
// users => []User{{ID: 0, Name: "jinzhu", Role: "", Salary: 100}, {ID: 0, Name: "jinzhu.2", Role: "", Salary: 1000}}

删除

删除一条记录
// Email 的 ID 是 `10`
db.Delete(&email)
// DELETE from emails where id = 10;

// 带额外条件的删除
db.Where("name = ?", "jinzhu").Delete(&email)
// DELETE from emails where id = 10 AND name = "jinzhu";

根据主键删除
db.Delete(&User{}, 10)
// DELETE FROM users WHERE id = 10;

db.Delete(&User{}, "10")
// DELETE FROM users WHERE id = 10;

db.Delete(&users, []int{1,2,3})
// DELETE FROM users WHERE id IN (1,2,3);

批量删除
db.Where("email LIKE ?", "%jinzhu%").Delete(Email{})
// DELETE from emails where email LIKE "%jinzhu%";

db.Delete(Email{}, "email LIKE ?", "%jinzhu%")
// DELETE from emails where email LIKE "%jinzhu%";

软删除
gorm.deletedatgorm.Model
DeleteDeletedAt
// user 的 ID 是 `111`
db.Delete(&user)
// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE id = 111;

// 批量删除
db.Where("age = ?", 20).Delete(&User{})
// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE age = 20;

// 在查询时会忽略被软删除的记录
db.Where("age = 20").Find(&user)
// SELECT * FROM users WHERE age = 20 AND deleted_at IS NULL;

gorm.Model
type User struct {
  ID      int
  Deleted gorm.DeletedAt
  Name    string
}
永久删除
db.Unscoped().Delete(&order)
// DELETE FROM orders WHERE id=10;

u%")
// DELETE from emails where email LIKE “%jinzhu%”;


##### 软删除

如果您的模型包含了一个 `gorm.deletedat` 字段(`gorm.Model` 已经包含了该字段),它将自动获得软删除的能力!

拥有软删除能力的模型调用 `Delete` 时,记录不会被数据库。但 GORM 会将 `DeletedAt` 置为当前时间, 并且你不能再通过普通的查询方法找到该记录。

```go
// user 的 ID 是 `111`
db.Delete(&user)
// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE id = 111;

// 批量删除
db.Where("age = ?", 20).Delete(&User{})
// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE age = 20;

// 在查询时会忽略被软删除的记录
db.Where("age = 20").Find(&user)
// SELECT * FROM users WHERE age = 20 AND deleted_at IS NULL;

gorm.Model
type User struct {
  ID      int
  Deleted gorm.DeletedAt
  Name    string
}
永久删除
db.Unscoped().Delete(&order)
// DELETE FROM orders WHERE id=10;