GORM 简单介绍
GORM 官方支持的数据库类型有: MySQL, PostgreSQL, SQlite, SQL Server
特性
• 全功能 ORM
• 关联 (Has One,Has Many,Belongs To,Many To Many,多态,单表继承)
• Create,Save,Update,Delete,Find 中钩子方法
• 支持 Preload、Joins 的预加载
• 事务,嵌套事务,Save Point,Rollback To Saved Point
• Context、预编译模式、DryRun 模式
• 批量插入,FindInBatches,Find/Create with Map,使用 SQL 表达式、Context Valuer 进
行 CRUD
• SQL 构建器,Upsert,数据库锁,Optimizer/Index/Comment Hint,命名参数,子查询
• 复合主键,索引,约束
• Auto Migration
• 自定义 Logger
• 灵活的可扩展插件 API:Database Resolver(多数据库,读写分离)、Prometheus…
• 每个特性都经过了测试的重重考验
• 开发者友好
GORM 指南 | GORM - The fantastic ORM library for Golang, aims to be developer friendly.https://gorm.io/zh_CN/docs/index.html
1、安装
go get -u gorm.io/gorm
go get -u gorm.io/driver/sqlite
使用go.mod管理的话,可以import后在编辑器加载(上述安装步骤可略)
2、Gin 中使用 Gorm 连接数据库
这段代码是在使用 Golang 中的 GORM 库连接到 MySQL 数据库,让我来解释一下:
1. `dsn := "用户:密码@tcp(ip:数据库端口)/库名?charset=utf8mb4&parseTime=True&loc=Local"`: 这里定义了一个数据源名称(DSN),包括了数据库的连接信息,用户名、密码、协议(tcp)、地址、端口、数据库名(gin)以及一些连接选项(charset=utf8mb4、parseTime=True、loc=Local)。
2. `DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})`: 这一行代码使用 GORM 库中的 `Open` 函数来连接到 MySQL 数据库。它使用了之前定义的数据源名称 `dsn`,并且传递了一个空的 `gorm.Config{}`,表示使用默认配置。
在这段代码中,GORM 是一个用于数据库操作的 Go 语言库,而 `mysql.Open(dsn)` 用于指定使用 MySQL 数据库,并且传递了之前定义的数据源名称。
连接成功后,`DB` 将包含一个数据库连接对象,`err` 将包含可能出现的错误信息。
core.go
package models
//这个操作是目的连接数据库,以及定义操作的是哪个库内的表
import (
// 我们使用了go.mod来管理包
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
// ----如果要全局使用数据库,需要先定义
var DB *gorm.DB
var err error
func init(){
// 连接数据库
// gin是你要选择的操作的库
dsn := "root:Hszp@123@tcp(127.0.0.1:3306)/gin?charset=utf8mb4&parseTime=True&loc=Local"
DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
// 上面不用冒号,因为上面已经定义了,直接赋值了
if err != nil {
fmt.Println(err)
}
}
3、定义操作数据库的模型
约定 | GORM - The fantastic ORM library for Golang, aims to be developer friendly.https://gorm.io/zh_CN/docs/conventions.html
虽然在 gorm 中可以指定字段的类型以及自动生成数据表,但是在实际的项目开发中,我们是先设计数据库表,然后去实现编码的。
在实际项目中定义数据库模型注意以下几点:
1、结构体的名称必须首字母大写 ,并和数据库表名称对应。例如:表名称为 user 结构体名称定义成 User,表名称为 article_cate 结构体名称定义成 ArticleCate
2、结构体中的字段名称首字母必须大写,并和数据库表中的字段一一对应。例如:下面结构体中的 Id 和数据库中的 id 对应,Username 和数据库中的 username 对应,Age 和数据库中的 age 对应,Email 和数据库中的 email 对应,AddTime 和数据库中的 add_time 字段对应
3、默认情况表名是结构体名称的复数形式。如果我们的结构体名称定义成 User,表示这个模型默认操作的是 users 表。
4、我们可以使用结构体中的自定义方法 TableName 改变结构体的默认表名称,如下:
func (User) TableName() string {
return "user"
}
表示把 User 结构体默认操作的表改为 user 表
定义 user 模型:
package models
// 定义的结构体要和数据库的表名字一致,且里面的字段要和数据库的字段一致,且大写
type User struct { //默认情况表名是结构体名称的复数形式;比如这个就是操作的表为users
Id int
Username string
Age int
Email string
AddTime int
}
// TableName 表示配置操作数据库的表名称
func (user User) TableName() string {
return "user"
}
我们准备测试的数据库:
4、全部查找以及按照条件查找
我们依旧使用之前的模块隔离的形式,使用之前的useraddcontroller.go控制器,以及adminrouter.go路由
adminrouter.go:
package routers
import (
"gindemo04/controllers/admin"
"gindemo04/middle"
"github.com/gin-gonic/gin"
)
func AdminRoutersInit(r *gin.Engine) {
//middlewares.InitMiddleware中间件
adminRouters := r.Group("/admin", middle.InitMiddleware)
{
adminRouters.GET("/", admin.IndexController{}.Index)
adminRouters.GET("/user", admin.UserAddController{}.Index)
adminRouters.GET("/user/add", admin.UserAddController{}.Add)
adminRouters.GET("/user/edit", admin.UserAddController{}.Edit)
adminRouters.GET("/user/delete", admin.UserAddController{}.Delete)
}
}
package admin
import (
"fmt"
"gindemo04/models"
"net/http"
"os"
"path"
"strconv"
"github.com/gin-gonic/gin"
)
type UserAddController struct {
BaseController
}
func (con UserAddController) Index(c *gin.Context) {
// 1、查询数据库
userList := []models.User{}
// FIND方法可以获取表内数据,然后赋值给userlist(切片)
models.DB.Find(&userList)
c.JSON(http.StatusOK, gin.H{
"result" : userList,
})
}
这段代码是使用 Golang 中的 Gin 框架和 GORM 库从数据库中检索用户数据并将其作为 JSON 响应返回。
1. `userList := []models.User{}`: 在这一行中,定义了一个空的 `userList` 切片,用于存储从数据库中检索到的用户数据。
2. `models.DB.Find(&userList)`: 这一行代码使用 GORM 库中的 `Find` 方法从数据库中检索用户数据,并将结果存储到 `userList` 中。`models.DB` 表示之前连接到数据库的 GORM 对象,`.Find` 方法用于执行查询操作,`&userList` 传递了切片的指针,以便查询结果可以被存储到切片中。
3. `c.JSON(http.StatusOK, gin.H{"result" : userList})`: 最后一行代码使用 Gin 框架中的 `c.JSON` 方法将查询结果作为 JSON 格式的响应返回。`http.StatusOK` 表示 HTTP 状态码为 200,`gin.H{"result" : userList}` 创建了一个包含查询结果的 JSON 对象,其中键为 "result",值为查询到的用户列表。
从数据库中检索用户数据,将其作为 JSON 格式的响应返回给客户端。
按照条件查找
查找年龄大于10的
package admin
import (
"fmt"
"gindemo04/models"
"net/http"
"os"
"path"
"strconv"
"github.com/gin-gonic/gin"
)
type UserAddController struct {
BaseController
}
func (con UserAddController) Index(c *gin.Context) {
// 2、按照条件进行查找(age>10)
userList := []models.User{}
models.DB.Where("age > ?",10).Find(&userList)
c.JSON(http.StatusOK, gin.H{
"result" : userList,
})
}
1. `userList := []models.User{}`: 在这一行中,定义了一个空的 `userList` 切片,用于存储从数据库中检索到的用户数据。
2. `models.DB.Where("age > ?",10).Find(&userList)`: 这一行代码使用 GORM 库中的 `Where` 方法指定了筛选条件,即年龄大于 10,然后使用 `Find` 方法从数据库中检索符合条件的用户数据,并将结果存储到 `userList` 中。`models.DB` 表示之前连接到数据库的 GORM 对象,`.Where("age > ?",10)` 指定了筛选条件,`Find` 方法用于执行查询操作,`&userList` 传递了切片的指针,以便查询结果可以被存储到切片中。
3. `c.JSON(http.StatusOK, gin.H{"result" : userList})`: 最后一行代码使用 Gin 框架中的 `c.JSON` 方法将查询结果作为 JSON 格式的响应返回。`http.StatusOK` 表示 HTTP 状态码为 200,`gin.H{"result" : userList}` 创建了一个包含查询结果的 JSON 对象,其中键为 "result",值为查询到的用户列表。
5、添加数据操作
实例化按照结构体内的数据
package admin
import (
"fmt"
"gindemo04/models"
"net/http"
"os"
"path"
"strconv"
"github.com/gin-gonic/gin"
)
type UserAddController struct {
BaseController
}
func (con UserAddController) Add(c *gin.Context) {
// c.HTML(http.StatusOK, "admin/useradd.html", gin.H{})
// //3、增加数据
user := models.User{
Id: 7,
Username: "芭乐",
Age: 19,
Email: "12213@qq.com",
AddTime: int(models.GetUnix()),
}
// 将数据插入到数据库中
models.DB.Create(&user)
c.JSON(http.StatusOK, gin.H{
"result" : "添加成功",
})
}
6、更新数据(save)
查询 | GORM - The fantastic ORM library for Golang, aims to be developer friendly.https://gorm.io/zh_CN/docs/query.html
package admin
import (
"fmt"
"gindemo04/models"
"net/http"
"os"
"path"
"strconv"
"github.com/gin-gonic/gin"
)
type UserAddController struct {
BaseController
}
}
func (con UserAddController) Edit(c *gin.Context) {
// //6、更新数据
//6.1查询id=5的数据
user := models.User{Id: 5}
models.DB.Find(&user)
fmt.Println(user)
c.JSON(http.StatusOK, gin.H{
"result" : user,
})
// //6.2更新数据(sava表示保存所有数据)
user.Username = "莫比---1"
models.DB.Save(&user)
c.JSON(http.StatusOK, gin.H{
"result" : "修改成功",
})
}
更新操作的单列形式
package admin
import (
"fmt"
"gindemo04/models"
"net/http"
"os"
"path"
"strconv"
"github.com/gin-gonic/gin"
)
type UserAddController struct {
BaseController
}
func (con UserAddController) Edit(c *gin.Context) {
user := models.User{}
//id=? 这是占位符
models.DB.Model(&user).Where("id = ?", 5).Update("username", "莫比")
c.JSON(http.StatusOK, gin.H{
"result" : "修改成功",
})
}
7、删除操作
where后面跟的字段要和数据库内字段匹配,而上面的修改操作需要和定义的结构体自动匹配,两个不一样
package admin
import (
"fmt"
"gindemo04/models"
"net/http"
"os"
"path"
"strconv"
"github.com/gin-gonic/gin"
)
type UserAddController struct {
BaseController
}
func (con UserAddController) Delete(c *gin.Context) {
//8、进行删除操作(where后面跟的字段要和数据库内字段匹配,而上面的修改操作需要和定义的结构体自动匹配,两个不一样)
user := models.User{}
models.DB.Where("id = ?", 5).Delete(&user)
c.JSON(http.StatusOK, gin.H{
"result" : "删除成功",
})
}