1.连接
需要下载MySQL的驱动
go get gorm.io/driver/mysql
go get gorm.io/gorm
简单连接
package gorm
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
var DB *gorm.DB
func Init() (*gorm.DB){
//1.
username := "root" //账号
password := "qwe123." //密码
host := "127.0.0.1" //数据库地址,可以是IP或者地址名
port := 3306 //端口号
Dbname := "xiangmu" //数据库名
timeout := "10s" //连接超时,10秒
//2.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)//转换为字符串
//3.连接MySQL,获得DB类型实例,用于后面的数据库读写操作
db, err := gorm.Open(mysql.Open(dsn))
if err != nil {
panic("连接数据库失败,error=" + err.Error())
}
//4.连接成功
DB=db
return DB
}
func main(){
包名.Init.PrintF
}
高级配置
跳过默认事务
为了确保数据一致性,GORM会在事务里执行写入操作(创建,更新,删除)。如果没有这方面的要求,可以在初始化时禁用它
这样还可以获得60%的性能提升
db,err:=gorm.Open(mysql.Open("gorm.db"),&gorm.Config{
SkipDefaultTransaction:true,
})
命名策略
gorm采用命名策略是,表名是蛇形复数,字段名是蛇形单数
例如:
var DB *gorm.DB
type Student struct{
ID uint
MyName string
Age int
}
func main(){
DB.AutoMigrate(&Student{})//创建表
}
gorm会为我们这样生成表结构
CREATE TABLE `students`(`id` bigint unsigned AUTO_INCREMENT ,`age` bigint,`my_sname` longtext,PRIMARY KEY(`id`))
我们也可以修改这些策略
db,err:=gorm.Open(mysql.Open(dsn),&gorm.Config{
NameingStrategy: schema.NamingStrategy{
TablePrefix: "f_",//表名前缀是什么
SingularTable: false,//是否单数表名
NoLowerCase: false,//是否关闭小写转换
}
})
2.显示日志
gorm的默认日志是只打印错误和慢SQL
我们可以自己设置
var mysqlLogger logger.Interface
//要显示的日志等级
mysqlLogger = logger.Default.LogMode(logger.Info)//Info是全局 占用资源多
db,err:=gorm.Open(mysql.Open(dsn),&gorm.Config{
Logger:mysqlLogger
})
如果你想要自定义日志的显示
那么可以使用如下代码
newLogger:=logger.New(
log.New(os.Stdout,"\r\n",log.LstdFlags),//(日志输出的目标,前缀和日志包含的内容)
logger.Config{
SLowThreshold: time.Second,//慢 SQL 阈值
LogLevel: logger.Info,//日志级别
IgnoreRecordNotFoundError: true, //忽略ErrRecordNotFound(记录未找到)错误
Colorful: true,//使用彩色打印
},
)
db,err:=gorm.Open(mysql.Open(dsn),&gorm.Config{
Logger:newLogger,
})
部分展示日志(用的多)
var model Student //要开启mysqlLogger = logger.Default.LogMode(logger.Info)
session:=DB.Session(&gorm.Session{Logger:newLogger})
session.First(&model)
实例
func main() {
DB = DB.Session(&gorm.Session{
Logger: mysqlLogger,
})
DB.AutoMigrate(&Student{})
}
如果只想某些语句显示日志
DB.Debug.First(&model)
//代码实例
func main() {
DB.Debug().AutoMigrate(&Student{}) //创建表
}
3.模型定义
模型是标准的struct,由go的基本数据类型,实现了Scanner和Valuer接口的自定义类型及其指针或别名组成
定义一张表
type Student struct{
ID uint//默认使用ID作为主键
Name string
Email *string//使用指针是为了存空值
}
常识:小写属性是不会生成字段的
自动生成表结构
//可以放多个
DB.AUtoMigrate(&Student{})
AutoMigrate的逻辑是新增,不删除,不修改(大小会修改)
例如将Name修改为Name1,进行迁移,会多出一个name1的字段
生成的表结构如下
CREATE TABLE `students`(`name` longtext,`id` bigint unsigned AUTO_INCREMENT,`name1` longtext,`email` longtext,PRIMARY KEY(`id`))
注意:默认的类型太大了
修改大小
我们可以使用gorm的标签进行修改
有两种方式
Name string `gorm:"type:vachar(12)"`
Name string `gorm:"size:2"`
字段标签
type 定义字段类型
size 定义字段大小
column 自定义列名
primaryKey 将列定义为主键
unique将列定义为唯一键
default 定义列的默认值
not null 不可为空
embedded 嵌套字段
embeddedPrefix 嵌套字段前缀
comment 注释
各个标签之前用;连接
type Student struct {
ID uint `gorm:size:10`
MyName string `gorm:size:16`
Age int `form:size:3`
Email *string `gorm:size:128`
Type string `gorm:column:type;size:4`
Date string `gorm:"default:2023-4-13;comment:日期"`
}
单表查询
先使用gorm对单张表进行增删改查
表结构
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"`
}
添加记录
email:="xx@qq.com"
//创建记录
Student:=Student{
Name: "小明",
Age:21,
Gender:true,
Email:&email,
}
DB.Create(&student)
有两个地方需要注意
- 指针类型是为了更好的存null类型,但是传值的时候,也记得传指针
- Create接收的是一个指针,而不是值
由于我们传递是一个指针,调用完Create后,student这个对象上面就有该记录的信息了,如创建的id
DB.Create(&student)
fmt.Printf("%#v\n",student)
//main.Studnet{ main.Person{ID:0x1, Name:"小明", Age:21, Gender:true, Email:(*string)(0xc0001da6c0)}}
批量插入
Create方法还可以用于插入多条记录
var Plist []Person
for i:=0;i<100;i++{
Plist = append(Plist,Person{
Name: fmt.Sprintf("学生:%d号",i+1),
Age:21+i+1,
Gender:true,
Email:&email,
})
}
DB.Create(&Plist)
查询单条记录
var P1 Person
DB.Take(&P1)
fmt.Println(P1)
获取单条记录的方法很多,我们对比sql就很直观了
DB=DB.Session(&gorm.Session{Logger:Log})
var P1 Person
DB.Take(&P1)//默认第一条
//SELECT *FROM `persons`LIMIT 1
P1=Person{}
DB.First(&P1)//默认第一条
//SELECT *FROM `persons` ORDER BY `persons`.`id` LIMIT 1
P1=Person{}
DB.Last(&P1)//默认最后一条
//SELECT *FROM `persons` ORDER BY `persons`.`id` DESCLIMIT 1
根据其他条件查询
var P1 Person
DB.Take(&P1,"name = ?","小明")
fmt.Println(P1)
使用?作为占位符,将查询的内容放入?
//SELECT *FROM `persons` WHERE name = "小明"LIMIT 1
这样可以有效的防止sql注入
他的原理就是将参数全部转义,如
DB.Take(&P1,"name = ?","小明'or 1=1;#1")
//SELECT * FROM `people` WHERE name='小明'or 1=1;#' LIMIT 1
根据struct查询
var P1 Person
//只能有一个主要值
Person.ID=2//只能根据主键去查
DB.Take(&P1)
fmt.Println(P1)
获取查询结果
获取查询的记录数
count:=DB.Find(Plist).RowsAffected
是否查询失败
err:=DB.Find(&Plist).Error
查询失败有查询为空,查询条件错误,sql语法错误
可以使用判断
var P1 Person
err:=DB.Take(&P1,"xx").Error
switch err{
case gorm.ErrRecordNotFound:
fmt.Println("没有找到")
default:
fmt.Println("sql错误")
}
查询多条记录
var PList []Person
DB.Find(&PList)
for_,p:=range PList{
fmt.Println(p)
}
//由于email是指针类型,所以看不到实际的内容
//但是序列号之后,会转换为我们可以看得懂的方式
var PList []Person
DB.Find(&PList)
for_,p:=range PList{
data,_:=json,Marshal(p)
fmt.Println(string(data))
}
根据主键列表查询
var PList []Person
DB.Find(&PList,[]int{1,3,5,7})
DB.Find(&PList,1,3,5,7)//一样的
fmt.Println(PList)
根据其他条件查询
DB.Find(&PList,"name in ?",[]string{"小明","小刘"})