简单连接
后面的代码都要基于这个简单连接的基础上进行编写。
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/schema"
)
var DB *gorm.DB
func init() {
username := "root1" //账号
password := "rootroot" //密码
host := "127.0.0.1" //数据库地址,可以是Ip或者域名
port := 3306 //数据库端口
DBname := "GoORM" //数据库名
timeout := "10s" //连接超时,10秒
// root:root@tcp(127.0.0.1:3306)/gorm?
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local&timeout=%s", username, password, host, port, DBname, timeout)
//连接MYSQL, 获得DB类型实例,用于后面的数据库读写操作。
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
//跳过默认事故,它默认是false,在初始化时禁用它,这样可以获得60%的性能提升
//SkipDefaultTransaction: true,
//如果不想自动以蛇形复数那些默认形式生成表,就写在这里面,不用可以注释掉
NamingStrategy: schema.NamingStrategy{
//TablePrefix: "f_", // 表名前缀
SingularTable: false, // 是否单数表名
NoLowerCase: true, // 是否关闭小写转换
},
})
if err != nil {
panic("连接数据库失败, error=" + err.Error())
}
DB = db
// 连接成功
//fmt.Println(db)
}
// gorm采用的命名策略是,表名是蛇形复数,字段名是蛇形单数
type Student struct {
ID uint
Name string
Age int
}
func main() {
//完成表的创建
DB.AutoMigrate(&Student{})
fmt.Println(DB)
}
显示日志
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"gorm.io/gorm/schema"
)
var DB *gorm.DB
var mysqlLogger logger.Interface
func init() {
username := "root1" //账号
password := "rootroot" //密码
host := "127.0.0.1" //数据库地址,可以是Ip或者域名
port := 3306 //数据库端口
DBname := "GoORM" //数据库名
timeout := "10s" //连接超时,10秒
//①加全局info,根据环境不同也可以显示不同日志,例如把info换成error,只看报错那些,但这样显示日志有点占用空间
//var mysqlLogger logger.Interface
mysqlLogger = logger.Default.LogMode(logger.Info)
// root:root@tcp(127.0.0.1:3306)/gorm?
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local&timeout=%s", username, password, host, port, DBname, timeout)
//连接MYSQL, 获得DB类型实例,用于后面的数据库读写操作。
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
//跳过默认事故,它默认是false,在初始化时禁用它,这样可以获得60%的性能提升
//SkipDefaultTransaction: true,
//如果不想自动以蛇形复数那些默认形式生成表,就写在这里面
NamingStrategy: schema.NamingStrategy{
//TablePrefix: "f_", // 表名前缀
SingularTable: false, // 是否单数表名
NoLowerCase: true, // 是否关闭小写转换
},
//Logger: mysqlLogger,
})
if err != nil {
panic("连接数据库失败, error=" + err.Error())
}
DB = db
// 连接成功
//fmt.Println(db)
}
// gorm采用的命名策略是,表名是蛇形复数,字段名是蛇形单数
type Student struct {
ID uint
Name string
Age int
}
func main() {
//②部分展示日志,这样相对来说就没那么占用空间
//DB = DB.Session(&gorm.Session{
// Logger: mysqlLogger,
//})
//完成表的创建,如果本身就有表,那么就不会再创建。
//DB.AutoMigrate(&Student{})
//③用Debug,这样就能局部让某个操作有日志。Debug本质就是创建了一个Session,把logger给放了进来
DB.Debug().AutoMigrate(&Student{})
fmt.Println(DB)
}
模型定义
定义一个表也就是定义一个struct,例如:
type Student struct {
ID uint
Name string
Age int
}
小写属性是不会生成字段的。
自动生成表结构
DB.AutoMigrate(&Student{})
AutoMigrate
的逻辑是只新增,不删除,不修改。
意味着如果struct
里把Name去掉换成Name1
,运行之后会发现Name1
和Name
都在,这就是只新增而不删除,不修改。
而且AutoMigrate
生成字段的类型都是大类型
所以要在struct
里用gorm
里的size
标签(但是表的主键可能会改不了,大概是因为数据库本身设计的问题。)
改完之后:
type Student struct {
ID uint `gorm:"size:16"`
Name string `gorm:"size:16"`
Age int `gorm:"size:3"`
Email *string `gorm:"size:128"`
}
//也可以自己定义类型,符合sql语句就行。
type Student struct {
ID uint `gorm:"size:16"`
Name string `gorm:"type:varchar(16)"`
Age int `gorm:"size:3"`
Email *string `gorm:"size:128"`
}
常用字段标签:
type
定义字段类型
size
定义字段大小
column
自定义列名
primaryKey
将列定义为主键
unique
将列定义为唯一键
default
定义列的默认值
not null
不可为空
embedded
嵌套字段
embeddedPrefix
嵌套字段前缀
comment
注释
多个标签之前用 ;
连接
使用案例:
type Student struct {
Name string `gorm:"type:varchar(12);not null;comment:用户名"`
UUID string `gorm:"primaryKey;unique;comment:主键"`
Info StudentInfo `gorm:"embedded;embeddedPrefix:s_"`
}
单表查询
添加记录:
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"gorm.io/gorm/schema"
)
var DB *gorm.DB
var mysqlLogger logger.Interface
func init() {
username := "root1" //账号
password := "rootroot" //密码
host := "127.0.0.1" //数据库地址,可以是Ip或者域名
port := 3306 //数据库端口
DBname := "GoORM" //数据库名
timeout := "10s" //连接超时,10秒
mysqlLogger = logger.Default.LogMode(logger.Info)
// root:root@tcp(127.0.0.1:3306)/gorm?
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local&timeout=%s", username, password, host, port, DBname, timeout)
//连接MYSQL, 获得DB类型实例,用于后面的数据库读写操作。
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
//跳过默认事故,它默认是false,在初始化时禁用它,这样可以获得60%的性能提升
//SkipDefaultTransaction: true,
//如果不想自动以蛇形复数那些默认形式生成表,就写在这里面
NamingStrategy: schema.NamingStrategy{
SingularTable: false, // 是否单数表名
NoLowerCase: true, // 是否关闭小写转换
},
})
if err != nil {
panic("连接数据库失败, error=" + err.Error())
}
DB = db
// 连接成功
}
type Student struct {
ID uint `gorm:"size:3"`
Name string `gorm:"size:8"`
Age int `gorm:"size:3"`
Gender bool
Email *string `gorm:"size:32"`
}
func main() {
//DB.AutoMigrate(&Student{})
DB = DB.Session(&gorm.Session{
Logger: mysqlLogger,
})
email := "rolingg@qq.com"
//添加记录
s1 := Student{
//其实ID也在。
Name: "RoLingG",
Age: 21,
Gender: true,
Email: &email,
}
err := DB.Create(&s1).Error
fmt.Println(err)
}
指针类型是为了更好的存储null
类型,但传值的时候还是一样,就是要记得传指针。
Create
接收的是一个指针,不是一个值
由于传的是一个指针,调用完create之后,st。udent这个对象上就有该记录的信息了,例如上述的ID。
批量插入
//批量插入
var studentList []Student
for i := 0; i < 10; i++ {
studentList = append(studentList, Student{
Name: fmt.Sprintf("RoLingG%d", i+1),
Age: 21 + i + 1,
Gender: true,
Email: nil,
})
}
err := DB.Create(&studentList).Error
fmt.Println(err)
单条记录查询
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"gorm.io/gorm/schema"
)
var DB *gorm.DB
var mysqlLogger logger.Interface
func init() {
username := "root1" //账号
password := "rootroot" //密码
host := "127.0.0.1" //数据库地址,可以是Ip或者域名
port := 3306 //数据库端口
DBname := "GoORM" //数据库名
timeout := "10s" //连接超时,10秒
mysqlLogger = logger.Default.LogMode(logger.Info)
// root:root@tcp(127.0.0.1:3306)/gorm?
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local&timeout=%s", username, password, host, port, DBname, timeout)
//连接MYSQL, 获得DB类型实例,用于后面的数据库读写操作。
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
//跳过默认事故,它默认是false,在初始化时禁用它,这样可以获得60%的性能提升
//SkipDefaultTransaction: true,
//如果不想自动以蛇形复数那些默认形式生成表,就写在这里面
NamingStrategy: schema.NamingStrategy{
SingularTable: false, // 是否单数表名
NoLowerCase: true, // 是否关闭小写转换
},
})
if err != nil {
panic("连接数据库失败, error=" + err.Error())
}
DB = db
// 连接成功
}
type Student struct {
ID uint `gorm:"size:3"`
Name string `gorm:"size:12"`
Age int `gorm:"size:3"`
Gender bool
Email *string `gorm:"size:32"`
}
func main() {
DB.AutoMigrate(&Student{})
DB = DB.Session(&gorm.Session{
Logger: mysqlLogger,
})
var student Student
//无顺序,默认按照ID查询
DB = DB.Session(&gorm.Session{Logger: mysqlLogger})
DB.Take(&student)
fmt.Println(student)
//直接这样写会和上面的student冲突,因为上面的student里已经有数据了
//DB.First(&student)
//fmt.Println(student)
//所以要重新赋值
student = Student{}
DB.First(&student)
fmt.Println(student)
student = Student{}
DB.Last(&student)
fmt.Println(student)
//根据主键自定义查询
student = Student{}
//将主键ID为2的拿出来查询
DB.Take(&student, 2)
//err := DB.Take(&student, 2).Error
//err := DB.Take(&student, 45).Error
fmt.Println(student)
//gorm.ErrRecordNotFound:一个bool值,用来看记录是否查询失败
//fmt.Println(err == gorm.ErrRecordNotFound)
//如果有错,则student返回的全是默认值,且会有error日志
//fmt.Println(err)
//根据name查询
student = Student{}
//用?进行拼接,尽量别用fmt.Sprintf()进行拼接,很容易造成查询失误导致数据泄露,用?作为占位符能有效的方式sql注入,?能进行转译限制。
DB.Take(&student, "Name = ?", "RoLingG9")
fmt.Println(student)
//根据struct查询
student = Student{}
//只能根据主要值查询,也就是主键
student.ID = 2
DB.Take(&student)
fmt.Println(student)
}
查询多条记录
切片即可
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"gorm.io/gorm/schema"
)
var DB *gorm.DB
var mysqlLogger logger.Interface
func init() {
username := "root1" //账号
password := "rootroot" //密码
host := "127.0.0.1" //数据库地址,可以是Ip或者域名
port := 3306 //数据库端口
DBname := "GoORM" //数据库名
timeout := "10s" //连接超时,10秒
mysqlLogger = logger.Default.LogMode(logger.Info)
// root:root@tcp(127.0.0.1:3306)/gorm?
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local&timeout=%s", username, password, host, port, DBname, timeout)
//连接MYSQL, 获得DB类型实例,用于后面的数据库读写操作。
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
//跳过默认事故,它默认是false,在初始化时禁用它,这样可以获得60%的性能提升
//SkipDefaultTransaction: true,
//如果不想自动以蛇形复数那些默认形式生成表,就写在这里面
NamingStrategy: schema.NamingStrategy{
SingularTable: false, // 是否单数表名
NoLowerCase: true, // 是否关闭小写转换
},
})
if err != nil {
panic("连接数据库失败, error=" + err.Error())
}
DB = db
// 连接成功
}
type Student struct {
ID uint `gorm:"size:3" json:"id"` //这里可以加json定义名字
Name string `gorm:"size:12" json:"name"`
Age int `gorm:"size:3"`
Gender bool
Email *string `gorm:"size:32"`
}
func main() {
DB.AutoMigrate(&Student{})
DB = DB.Session(&gorm.Session{
Logger: mysqlLogger,
})
//查询多条数据
var studentList []Student
count := DB.Find(&studentList)
fmt.Println(count)
for _, student := range studentList {
fmt.Println(student)
}
//json的形式
//json形式可以看到指针转译的值,例如这里的邮箱,普通是输出是看的是机器码,而json输出看的是实际值
data, _ := json.Marshal(studentList)
fmt.Println(string(data))
}
根据id查询、name查询:
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"gorm.io/gorm/schema"
)
var DB *gorm.DB
var mysqlLogger logger.Interface
func init() {
username := "root1" //账号
password := "rootroot" //密码
host := "127.0.0.1" //数据库地址,可以是Ip或者域名
port := 3306 //数据库端口
DBname := "GoORM" //数据库名
timeout := "10s" //连接超时,10秒
mysqlLogger = logger.Default.LogMode(logger.Info)
// root:root@tcp(127.0.0.1:3306)/gorm?
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local&timeout=%s", username, password, host, port, DBname, timeout)
//连接MYSQL, 获得DB类型实例,用于后面的数据库读写操作。
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
//跳过默认事故,它默认是false,在初始化时禁用它,这样可以获得60%的性能提升
//SkipDefaultTransaction: true,
//如果不想自动以蛇形复数那些默认形式生成表,就写在这里面
NamingStrategy: schema.NamingStrategy{
SingularTable: false, // 是否单数表名
NoLowerCase: true, // 是否关闭小写转换
},
})
if err != nil {
panic("连接数据库失败, error=" + err.Error())
}
DB = db
// 连接成功
}
type Student struct {
ID uint `gorm:"size:3" json:"id"` //这里可以加json定义名字
Name string `gorm:"size:12" json:"name"`
Age int `gorm:"size:3"`
Gender bool
Email *string `gorm:"size:32"`
}
func main() {
DB.AutoMigrate(&Student{})
DB = DB.Session(&gorm.Session{
Logger: mysqlLogger,
})
//查询多条数据
var studentList []Student
count := DB.Find(&studentList)
fmt.Println(count)
for _, student := range studentList {
fmt.Println(student)
}
//根据id列表查
DB.Find(&studentList, []int{4, 7, 9})
fmt.Println(studentList)
//根据name查
DB.Find(&studentList, "name in (?)", []string{"RoLingG1", "RoLingG2", "RoLingG8"})
fmt.Println(studentList)
}
各类操作
更新操作
save
保存所有字段
用于单个记录(数据)的全字段更新
会保存所有字段,即使是零值也会保存
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"gorm.io/gorm/schema"
)
var DB *gorm.DB
var mysqlLogger logger.Interface
func init() {
username := "root1" //账号
password := "rootroot" //密码
host := "127.0.0.1" //数据库地址,可以是Ip或者域名
port := 3306 //数据库端口
DBname := "GoORM" //数据库名
timeout := "10s" //连接超时,10秒
mysqlLogger = logger.Default.LogMode(logger.Info)
// root:root@tcp(127.0.0.1:3306)/gorm?
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local&timeout=%s", username, password, host, port, DBname, timeout)
//连接MYSQL, 获得DB类型实例,用于后面的数据库读写操作。
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
//跳过默认事故,它默认是false,在初始化时禁用它,这样可以获得60%的性能提升
//SkipDefaultTransaction: true,
//如果不想自动以蛇形复数那些默认形式生成表,就写在这里面
NamingStrategy: schema.NamingStrategy{
SingularTable: false, // 是否单数表名
NoLowerCase: true, // 是否关闭小写转换
},
})
if err != nil {
panic("连接数据库失败, error=" + err.Error())
}
DB = db
// 连接成功
}
type Student struct {
ID uint `gorm:"size:3" json:"id"` //这里可以加json定义名字
Name string `gorm:"size:12" json:"name"`
Age int `gorm:"size:3"`
Gender bool
Email *string `gorm:"size:32"`
}
func main() {
DB.AutoMigrate(&Student{})
DB = DB.Session(&gorm.Session{
Logger: mysqlLogger,
})
//save更新
var student Student
DB.Take(&student, 10)
student.Email = nil
student.Age = 0
student.Name = "Clouwer"
DB.Save(&student)
//限定某个字段进行更新
student.Email = nil
student.Age = 31 //Age字段为0,并没有改成31
student.Name = "RoLingG"
DB.Select("Name").Save(&student)
}
update/updates
更新多个记录
常用于批量更新,以及更新多列
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"gorm.io/gorm/schema"
)
var DB *gorm.DB
var mysqlLogger logger.Interface
func init() {
username := "root1" //账号
password := "rootroot" //密码
host := "127.0.0.1" //数据库地址,可以是Ip或者域名
port := 3306 //数据库端口
DBname := "GoORM" //数据库名
timeout := "10s" //连接超时,10秒
mysqlLogger = logger.Default.LogMode(logger.Info)
// root:root@tcp(127.0.0.1:3306)/gorm?
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local&timeout=%s", username, password, host, port, DBname, timeout)
//连接MYSQL, 获得DB类型实例,用于后面的数据库读写操作。
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
//跳过默认事故,它默认是false,在初始化时禁用它,这样可以获得60%的性能提升
//SkipDefaultTransaction: true,
//如果不想自动以蛇形复数那些默认形式生成表,就写在这里面
NamingStrategy: schema.NamingStrategy{
SingularTable: false, // 是否单数表名
NoLowerCase: true, // 是否关闭小写转换
},
})
if err != nil {
panic("连接数据库失败, error=" + err.Error())
}
DB = db
// 连接成功
}
type Student struct {
ID uint `gorm:"size:3" json:"id"` //这里可以加json定义名字
Name string `gorm:"size:12" json:"name"`
Age int `gorm:"size:3"`
Gender bool
Email *string `gorm:"size:32"`
}
func main() {
DB.AutoMigrate(&Student{})
DB = DB.Session(&gorm.Session{
Logger: mysqlLogger,
})
//update更新
var studentList []Student
//DB.Find(&studentList, []int{7, 8, 9}).Update("Email", "11223344@qq.com")
//updates更新多列、多字段(updates传的是结构体时,更新为零值是不会更改的。而传的map时,是可以更改的)
//用结构体进行数据传输
//DB.Find(&studentList, []int{7, 8, 9}).Updates(Student{
// Name: "Clouwer",
// Age: 19,
// Gender: false,
//})
//用map进行数据传输
DB.Find(&studentList, []int{7, 8, 9}).Updates(map[string]any{
"Name": "Clouwer123",
})
}
删除操作
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"gorm.io/gorm/schema"
)
var DB *gorm.DB
var mysqlLogger logger.Interface
func init() {
username := "root1" //账号
password := "rootroot" //密码
host := "127.0.0.1" //数据库地址,可以是Ip或者域名
port := 3306 //数据库端口
DBname := "GoORM" //数据库名
timeout := "10s" //连接超时,10秒
mysqlLogger = logger.Default.LogMode(logger.Info)
// root:root@tcp(127.0.0.1:3306)/gorm?
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local&timeout=%s", username, password, host, port, DBname, timeout)
//连接MYSQL, 获得DB类型实例,用于后面的数据库读写操作。
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
//跳过默认事故,它默认是false,在初始化时禁用它,这样可以获得60%的性能提升
//SkipDefaultTransaction: true,
//如果不想自动以蛇形复数那些默认形式生成表,就写在这里面
NamingStrategy: schema.NamingStrategy{
SingularTable: false, // 是否单数表名
NoLowerCase: true, // 是否关闭小写转换
},
})
if err != nil {
panic("连接数据库失败, error=" + err.Error())
}
DB = db
// 连接成功
}
type Student struct {
ID uint `gorm:"size:3" json:"id"` //这里可以加json定义名字
Name string `gorm:"size:12" json:"name"`
Age int `gorm:"size:3"`
Gender bool
Email *string `gorm:"size:32"`
}
func main() {
DB.AutoMigrate(&Student{})
DB = DB.Session(&gorm.Session{
Logger: mysqlLogger,
})
//delete删除
var student Student
//单个删除
DB.Delete(&student, 10)
//批量删除
DB.Delete(&student, []int{7, 8, 9})
//常用的从表头顺序删除
DB.Take(&student)
DB.Delete(&student)
}
钩子函数
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"gorm.io/gorm/schema"
)
var DB *gorm.DB
var mysqlLogger logger.Interface
func init() {
username := "root1" //账号
password := "rootroot" //密码
host := "127.0.0.1" //数据库地址,可以是Ip或者域名
port := 3306 //数据库端口
DBname := "GoORM" //数据库名
timeout := "10s" //连接超时,10秒
mysqlLogger = logger.Default.LogMode(logger.Info)
// root:root@tcp(127.0.0.1:3306)/gorm?
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local&timeout=%s", username, password, host, port, DBname, timeout)
//连接MYSQL, 获得DB类型实例,用于后面的数据库读写操作。
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
//跳过默认事故,它默认是false,在初始化时禁用它,这样可以获得60%的性能提升
//SkipDefaultTransaction: true,
//如果不想自动以蛇形复数那些默认形式生成表,就写在这里面
NamingStrategy: schema.NamingStrategy{
SingularTable: false, // 是否单数表名
NoLowerCase: true, // 是否关闭小写转换
},
})
if err != nil {
panic("连接数据库失败, error=" + err.Error())
}
DB = db
// 连接成功
}
type Student struct {
ID uint `gorm:"size:3" json:"id"` //这里可以加json定义名字
Name string `gorm:"size:12" json:"name"`
Age int `gorm:"size:3"`
Gender bool
Email *string `gorm:"size:32"`
}
func (user *Student) BeforeCreate(tx *gorm.DB) (err error) {
Email := "test@qq.com"
user.Email = &Email
return nil
}
func main() {
DB.AutoMigrate(&Student{})
DB = DB.Session(&gorm.Session{
Logger: mysqlLogger,
})
//创建hook(钩子函数)
//用hook在插入数据表前做一些事情(这里的举例是在表创建之前给一些数据赋值进行创建)
Emailtest := "testest@qq.com"
DB.Create(&Student{
Name: "Clouwer100",
Age: 23,
Email: &Emailtest, //没用,该值早就被赋值了
})
}
高级查询
Where:等价于SQL语句中的where查询
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"gorm.io/gorm/schema"
)
var DB *gorm.DB
var mysqlLogger logger.Interface
func init() {
username := "root1" //账号
password := "rootroot" //密码
host := "127.0.0.1" //数据库地址,可以是Ip或者域名
port := 3306 //数据库端口
DBname := "GoORM" //数据库名
timeout := "10s" //连接超时,10秒
mysqlLogger = logger.Default.LogMode(logger.Info)
// root:root@tcp(127.0.0.1:3306)/gorm?
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local&timeout=%s", username, password, host, port, DBname, timeout)
//连接MYSQL, 获得DB类型实例,用于后面的数据库读写操作。
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
//跳过默认事故,它默认是false,在初始化时禁用它,这样可以获得60%的性能提升
//SkipDefaultTransaction: true,
//如果不想自动以蛇形复数那些默认形式生成表,就写在这里面
NamingStrategy: schema.NamingStrategy{
SingularTable: false, // 是否单数表名
NoLowerCase: true, // 是否关闭小写转换
},
})
if err != nil {
panic("连接数据库失败, error=" + err.Error())
}
DB = db
// 连接成功
}
type Student struct {
ID uint `gorm:"size:3" json:"id"` //这里可以加json定义名字
Name string `gorm:"size:12" json:"name"`
Age int `gorm:"size:3"`
Gender bool
Email *string `gorm:"size:32"`
}
func PtrString(email string) *string {
return &email
}
func main() {
//日志显示
DB = DB.Session(&gorm.Session{
Logger: mysqlLogger,
})
//先创建表,创完就可以注释掉了
//var studentList []Student
//DB.Find(&studentList).Delete(&studentList)
//studentList = []Student{ //注意,go语言的切片,最先被初始化的最后被输出,所以要顺序执行得逆向写。
// {ID: 9, Name: "克劳德", Age: 32, Email: PtrString("lyf@qq.com"), Gender: true},
// {ID: 8, Name: "扎克斯", Age: 18, Email: PtrString("zhangwu@qq.cn"), Gender: true},
// {ID: 7, Name: "爱丽丝", Age: 23, Email: PtrString("ff@163.com"), Gender: false},
// {ID: 6, Name: "蒂法", Age: 54, Email: PtrString("liuda@qq.com"), Gender: false},
// {ID: 5, Name: "萨菲罗斯", Age: 23, Email: PtrString("liwu@lly.cn"), Gender: true},
// {ID: 4, Name: "李衣李", Age: 14, Email: PtrString("liqi@qq.com"), Gender: false},
// {ID: 3, Name: "克里克", Age: 25, Email: PtrString("xiaomeo@qq.com"), Gender: true},
// {ID: 2, Name: "阿童木", Age: 26, Email: PtrString("ruyan@yf.com"), Gender: true},
// {ID: 1, Name: "盖克特", Age: 21, Email: PtrString("moling@sl.com"), Gender: true},
//}
//DB.Create(&studentList)
var students []Student
// 查询用户名是盖克特的
// select * from students where name = ‘盖克特‘
DB.Where("name = ?", "盖克特").Find(&students)
fmt.Println(students)
// 查询用户名不是盖克特的(三种写法,三条都等价)
// select * from students where not name = ‘盖克特’
//fmt.Println(DB.Not("name = ?", "盖克特").Find(&students).RowsAffected)
//DB.Where("not name = ?", "盖克特").Find(&students)
DB.Where("name <> ?", "盖克特").Find(&students)
fmt.Println(students)
// 查询用户名包含 李衣李,克里克(这里的?不用加`()`,但是Find方法这样写就要加`()`)
// select * from students where name in (‘李衣李’,‘克里克’)
//DB.Find(&students, "name = (?)", []string{"李衣李", "克里克"})
DB.Where("name in ?", []string{"李衣李", "克里克"}).Find(&students)
fmt.Println(students)
// 查询姓李的(两种方法:%号不限字数,_有多少个就多查多少个)
// select * from students where name like ‘李%’
//DB.Where("name like ?", "李__").Find(&students)
DB.Where("name like ?", "李%").Find(&students)
fmt.Println(students)
// 查询年龄大于23,是qq邮箱的
// select * from student where age > 23 and email like '%@qq.com'
DB.Where("age > ? and email like ?", "23", "%@qq.com").Find(&students)
fmt.Println(students)
// 查询是qq邮箱的,或者是女的
// select * from student where age > 23 or gender = 'false'
DB.Where("gender = ? or email like ?", false, "%@qq.com").Find(&students)
//DB.Where("gender = ?").Or("email like ?", false, "%@qq.com").Find(&students)
fmt.Println(students)
}
使用结构体查询
使用结构体查询,会过滤零值
并且结构体中的条件都是and关系
//使用结构体查询
//会过滤零值
DB.Where(&Student{Name: "蒂法", Age: 54}).Find(&students)
fmt.Println(students)
DB.Where(&Student{Name: "克劳德", Age: 0}).Find(&students)
fmt.Println(students)
//[0.000ms] [rows:1] SELECT * FROM `Students` WHERE `Students`.`Name` = '蒂法' AND`Students`.`Age` = 54
//[{6 蒂法 54 false 0xc00021b2f0}]
//[0.000ms] [rows:1] SELECT * FROM `Students` WHERE `Students`.`Name` = '克劳德'
//[{9 克劳德 32 true 0xc00021b400}]
使用Map查询
不会过滤零值
//使用Map查询
//不会过滤零值
DB.Where(map[string]any{"Name": "克劳德", "Age": 32}).Find(&students)
fmt.Println(students)
DB.Where(map[string]any{"Name": "克劳德", "Age": 0}).Find(&students)
fmt.Println(students)
//[0.000ms] [rows:1] SELECT * FROM `Students` WHERE `Age` = 32 AND `Name` = '克劳德'
//[{9 克劳德 32 true 0xc00021b520}]
//[0.000ms] [rows:0] SELECT * FROM `Students` WHERE `Age` = 0 AND `Name` = '克劳德'
//[]
使用select部分属性查询
//使用部分字段查询(Find查询是直接查全部)
//select一个属性,这样只有那个属性是真实值,其他没有select的全是零值/空值
DB.Select("Name").Find(&students)
fmt.Println(students)
//传多个属性
DB.Select("Name", "Age").Find(&students)
fmt.Println(students)
//传一个切片
DB.Select([]string{"Name", "Age"}).Find(&students)
fmt.Println(students)
//写一个小的结构体,去做到部分属性查询
type PartInfo1 struct {
Name string
Age int
}
var info1 []PartInfo1
//这样写会select两次,这是这种方法的弊端
DB.Select("Name", "Age").Find(&students).Scan(&info1) //要有Find的原因是因为要知道表名
fmt.Println(students)
//当知道表名时可以这样↓,和上面操作等价
DB.Table("students").Select("Name", "Age").Scan(&info1)
fmt.Println(students)
//下面这个就是改进方法,只会select一次
type PartInfo2 struct {
Name string
Age int
}
var info2 []PartInfo2
DB.Model(&Student{}).Select("Name", "Age").Scan(&info2)
fmt.Println(students)
注意:
//Scan是根据列名扫描的
//例子
type PartInfo2 struct {
//Name1 string //按道理来说应该查不到,但是这里能,我也不清楚
Name1 string `gorm:"column:Name"` //按道理来说应该这样写才查询的到
Age int
}
var info2 []PartInfo2
DB.Model(&Student{}).Select("Name", "Age").Scan(&info2)
fmt.Println(students)
排序
desc:降序
asc:升序
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"gorm.io/gorm/schema"
)
var DB *gorm.DB
var mysqlLogger logger.Interface
func init() {
username := "root1" //账号
password := "rootroot" //密码
host := "127.0.0.1" //数据库地址,可以是Ip或者域名
port := 3306 //数据库端口
DBname := "GoORM" //数据库名
timeout := "10s" //连接超时,10秒
mysqlLogger = logger.Default.LogMode(logger.Info)
// root:root@tcp(127.0.0.1:3306)/gorm?
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local&timeout=%s", username, password, host, port, DBname, timeout)
//连接MYSQL, 获得DB类型实例,用于后面的数据库读写操作。
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
//跳过默认事故,它默认是false,在初始化时禁用它,这样可以获得60%的性能提升
//SkipDefaultTransaction: true,
//如果不想自动以蛇形复数那些默认形式生成表,就写在这里面
NamingStrategy: schema.NamingStrategy{
SingularTable: false, // 是否单数表名
NoLowerCase: true, // 是否关闭小写转换
},
})
if err != nil {
panic("连接数据库失败, error=" + err.Error())
}
DB = db
// 连接成功
}
type Student struct {
ID uint `gorm:"size:3" json:"id"` //这里可以加json定义名字
Name string `gorm:"size:12" json:"name"`
Age int `gorm:"size:3"`
Gender bool
Email *string `gorm:"size:32"`
}
func PtrString(email string) *string {
return &email
}
func main() {
//日志显示
DB = DB.Session(&gorm.Session{
Logger: mysqlLogger,
})
var studentList []Student
//降序
//DB.Order("Age desc").Find(&studentList)
//升序
DB.Order("Age asc").Find(&studentList)
fmt.Println(&studentList)
}
分页查询
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"gorm.io/gorm/schema"
)
var DB *gorm.DB
var mysqlLogger logger.Interface
func init() {
username := "root1" //账号
password := "rootroot" //密码
host := "127.0.0.1" //数据库地址,可以是Ip或者域名
port := 3306 //数据库端口
DBname := "GoORM" //数据库名
timeout := "10s" //连接超时,10秒
mysqlLogger = logger.Default.LogMode(logger.Info)
// root:root@tcp(127.0.0.1:3306)/gorm?
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local&timeout=%s", username, password, host, port, DBname, timeout)
//连接MYSQL, 获得DB类型实例,用于后面的数据库读写操作。
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
//跳过默认事故,它默认是false,在初始化时禁用它,这样可以获得60%的性能提升
//SkipDefaultTransaction: true,
//如果不想自动以蛇形复数那些默认形式生成表,就写在这里面
NamingStrategy: schema.NamingStrategy{
SingularTable: false, // 是否单数表名
NoLowerCase: true, // 是否关闭小写转换
},
})
if err != nil {
panic("连接数据库失败, error=" + err.Error())
}
DB = db
// 连接成功
}
type Student struct {
ID uint `gorm:"size:3" json:"id"` //这里可以加json定义名字
Name string `gorm:"size:12" json:"name"`
Age int `gorm:"size:3"`
Gender bool
Email *string `gorm:"size:32"`
}
func PtrString(email string) *string {
return &email
}
func main() {
//日志显示
DB = DB.Session(&gorm.Session{
Logger: mysqlLogger,
})
var studentList []Student
//分页查询
// select id, name, age students limit 2 和下面等价
// select id, name, age students limit 2 offset 0 第一页 2指一页只能有2行 0指从第0行开始
// select id, name, age students limit 2 offset 2 第二页 2指一页只能有2行 2指从第2行开始
// select id, name, age students limit 2 offset 4 第三页 ......
// select id, name, age students limit 2 offset 6 第四页 ......
DB.Limit(2).Offset(0).Find(&studentList) //和上面SQL语句一样
fmt.Println(&studentList)
DB.Limit(2).Offset(2).Find(&studentList) //和上面SQL语句一样
fmt.Println(&studentList)
DB.Limit(2).Offset(4).Find(&studentList) //和上面SQL语句一样
fmt.Println(&studentList)
//......
}
通用写法:
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"gorm.io/gorm/schema"
)
var DB *gorm.DB
var mysqlLogger logger.Interface
func init() {
username := "root1" //账号
password := "rootroot" //密码
host := "127.0.0.1" //数据库地址,可以是Ip或者域名
port := 3306 //数据库端口
DBname := "GoORM" //数据库名
timeout := "10s" //连接超时,10秒
mysqlLogger = logger.Default.LogMode(logger.Info)
// root:root@tcp(127.0.0.1:3306)/gorm?
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local&timeout=%s", username, password, host, port, DBname, timeout)
//连接MYSQL, 获得DB类型实例,用于后面的数据库读写操作。
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
//跳过默认事故,它默认是false,在初始化时禁用它,这样可以获得60%的性能提升
//SkipDefaultTransaction: true,
//如果不想自动以蛇形复数那些默认形式生成表,就写在这里面
NamingStrategy: schema.NamingStrategy{
SingularTable: false, // 是否单数表名
NoLowerCase: true, // 是否关闭小写转换
},
})
if err != nil {
panic("连接数据库失败, error=" + err.Error())
}
DB = db
// 连接成功
}
type Student struct {
ID uint `gorm:"size:3" json:"id"` //这里可以加json定义名字
Name string `gorm:"size:12" json:"name"`
Age int `gorm:"size:3"`
Gender bool
Email *string `gorm:"size:32"`
}
func PtrString(email string) *string {
return &email
}
func main() {
//日志显示
DB = DB.Session(&gorm.Session{
Logger: mysqlLogger,
})
//先创建表,创完就可以注释掉了
var studentList []Student
//分页查询的通用写法
limit := 2
page := 1
//offset那是一个偏移的计算,其实就是每页多少行,然后根据行数来进行分页计算
DB.Limit(limit).Offset((page - 1) * limit).Find(&studentList)
fmt.Println(&studentList)
}
去重
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"gorm.io/gorm/schema"
)
var DB *gorm.DB
var mysqlLogger logger.Interface
func init() {
username := "root1" //账号
password := "rootroot" //密码
host := "127.0.0.1" //数据库地址,可以是Ip或者域名
port := 3306 //数据库端口
DBname := "GoORM" //数据库名
timeout := "10s" //连接超时,10秒
mysqlLogger = logger.Default.LogMode(logger.Info)
// root:root@tcp(127.0.0.1:3306)/gorm?
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local&timeout=%s", username, password, host, port, DBname, timeout)
//连接MYSQL, 获得DB类型实例,用于后面的数据库读写操作。
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
//跳过默认事故,它默认是false,在初始化时禁用它,这样可以获得60%的性能提升
//SkipDefaultTransaction: true,
//如果不想自动以蛇形复数那些默认形式生成表,就写在这里面
NamingStrategy: schema.NamingStrategy{
SingularTable: false, // 是否单数表名
NoLowerCase: true, // 是否关闭小写转换
},
})
if err != nil {
panic("连接数据库失败, error=" + err.Error())
}
DB = db
// 连接成功
}
type Student struct {
ID uint `gorm:"size:3" json:"id"` //这里可以加json定义名字
Name string `gorm:"size:12" json:"name"`
Age int `gorm:"size:3"`
Gender bool
Email *string `gorm:"size:32"`
}
func PtrString(email string) *string {
return &email
}
func main() {
//日志显示
DB = DB.Session(&gorm.Session{
Logger: mysqlLogger,
})
//去重
//select distinct age from students
var ageList []int
//写法一
//DB.Model(Student{}).Select("Age").Distinct("Age").Scan(&ageList)
//[0.720ms] [rows:8] SELECT DISTINCT `Age` FROM `Students`
//&[21 26 25 14 23 54 18 32]
//写法二
DB.Model(Student{}).Select("distinct Age").Scan(&ageList)
//[1.511ms] [rows:8] SELECT distinct Age FROM `Students`
//&[21 26 25 14 23 54 18 32]
fmt.Println(&ageList)
}
分组查询
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"gorm.io/gorm/schema"
)
var DB *gorm.DB
var mysqlLogger logger.Interface
func init() {
username := "root1" //账号
password := "rootroot" //密码
host := "127.0.0.1" //数据库地址,可以是Ip或者域名
port := 3306 //数据库端口
DBname := "GoORM" //数据库名
timeout := "10s" //连接超时,10秒
mysqlLogger = logger.Default.LogMode(logger.Info)
// root:root@tcp(127.0.0.1:3306)/gorm?
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local&timeout=%s", username, password, host, port, DBname, timeout)
//连接MYSQL, 获得DB类型实例,用于后面的数据库读写操作。
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
//跳过默认事故,它默认是false,在初始化时禁用它,这样可以获得60%的性能提升
//SkipDefaultTransaction: true,
//如果不想自动以蛇形复数那些默认形式生成表,就写在这里面
NamingStrategy: schema.NamingStrategy{
SingularTable: false, // 是否单数表名
NoLowerCase: true, // 是否关闭小写转换
},
})
if err != nil {
panic("连接数据库失败, error=" + err.Error())
}
DB = db
// 连接成功
}
type Student struct {
ID uint `gorm:"size:3" json:"id"` //这里可以加json定义名字
Name string `gorm:"size:12" json:"name"`
Age int `gorm:"size:3"`
Gender bool
Email *string `gorm:"size:32"`
}
func PtrString(email string) *string {
return &email
}
func main() {
//日志显示
DB = DB.Session(&gorm.Session{
Logger: mysqlLogger,
})
//分组查询
var GenderList []int
//查询男女生个数
DB.Table("students").Select("count(id)").Group("Gender").Scan(&GenderList)
fmt.Println(&GenderList)
//&[6 3]
//但这样我们不知道哪个是男哪个是女的个数
}
详细一点:
func main() {
//日志显示
DB = DB.Session(&gorm.Session{
Logger: mysqlLogger,
})
//分组查询
var GenderList []int
//查询男女生个数
DB.Table("students").Select("count(id)").Group("Gender").Scan(&GenderList)
fmt.Println(&GenderList)
//&[6 3]
//但这样我们不知道哪个是男哪个是女的个数
//这样相对来说更精确一点
type Group struct {
Count int
Gender string
}
var GroupList []Group
DB.Model(Student{}).Select("Gender", "count(id) as Count").Group("Gender").Scan(&GroupList)
fmt.Println(GroupList)
}
更详细一点:
func main() {
//日志显示
DB = DB.Session(&gorm.Session{
Logger: mysqlLogger,
})
//更精确一点
type Group struct {
Count int
Gender string
NameList string
}
var GroupList []Group
DB.Model(Student{}).
Select(
"group_concat(Name) as NameList",
"Gender",
"count(id) as Count",
).
Group("Gender").
Scan(&GroupList)
fmt.Println(GroupList)
//[0.506ms] [rows:2] SELECT group_concat(Name) as NameList,`Gender`,count(id) as Count FROM `Students` GROUP BY `Gender`
//[{3 0 李衣李,蒂法,爱丽丝} {6 1 盖克特,阿童木,克里克,萨菲罗斯,扎克斯,克劳德}]
}
Gorm框架的好处:贴近原生SQL的编写
执行原生SQL语句
//执行原生SQL语句
type Group struct {
Count int
Gender string
NameList string
}
var GroupList []Group
DB.Raw("SELECT group_concat(name) as NameList, `Gender`,count(id) as Count FROM `Students` GROUP BY `Gender`").Scan(&GroupList)
fmt.Println(GroupList)
//哪里要拼接就用?进行传递
子查询
获取上一个查询作为参数进行下一个查询
//子查询
var studentList []Student
//原生sql
//select * from students where age > (select avg(age) from students);
DB.Model(Student{}).Where("age > (?)", DB.Model(Student{}).Select("avg(Age)")).Find(&studentList)
fmt.Println(studentList)
命名参数
//命名参数
var users []Student
//@具名参数,?不具名参数
DB.Where("Name = @name and Age = @age", sql.Named("name", "克劳德"), sql.Named("age", 32)).Find(&users)
fmt.Println(users)
//map的形式,更简短也更简洁,而且可以进一步的封装
DB.Where("Name = @name and Age = @age", map[string]any{"name": "盖克特", "age": 21}).Find(&users)
fmt.Println(users)
find到map
//find到map
var res []map[string]any //转成的类型随意,json那些都可以
DB.Table("students").Find(&res)
fmt.Println(res)
查询引用Scope
func main() {
......
var Map []map[string]any
//DB.Table("students").Find(&res)
//查询引用Scope
DB.Table("students").Scopes(FindAge23).Find(&Map)
fmt.Println(Map)
}
// 这里相当于封装语句,然后再Scopes里链式调用
func FindAge23(db *gorm.DB) *gorm.DB {
return db.Where("age > ?", 23)
}
评论(0)