1 Introduction
SNAKE
Object-Relationl Mapping, its role is the mapping between databases and object to help us in the realization of database operations do not have to write complex sql statement, to rise to the operation of the database operations for the object.
blue
gorm is based ORM library Go language.
Similar to the Java ecosystem where everyone heard Mybatis, Hibernate, SpringData and so on.
Github
https://github.com/jinzhu/gorm
Official Documents
https://gorm.io/
2, how to use Gorm
Just 4 steps to get started gorm, you can enjoy the CRUD immersed in the world there is no technical content.
2.1 download gorm library
Download Library gorm
go get -u github.com/jinzhu/gorm
This is a rather primitive way, now have go mod, we can more easily configure, even without configuration.
Written code at execution go build file, go.mod automatically added to gorm dependencies
github.com/jinzhu/gorm v1.9.10
Of course, you can also manually add this dependency.
Referring specifically to go-demo project (https://github.com/DMinerJackie/go-demo)
2.2 Creating DB Connection
Establish a database connection
package main import ( "github.com/jinzhu/gorm" _ "github.com/jinzhu/gorm/dialects/mysql" ) func main() { var err error db, connErr := gorm.Open("mysql", "root:rootroot@/dqm?charset=utf8&parseTime=True&loc=Local") if connErr != nil { panic("failed to connect database") } defer db.Close() db.SingularTable(true) }
gorm supports many data sources, including PostgreSQL, MySQL and so on.
The connection here is MySQL, so you need to reference "github.com/jinzhu/gorm/dialects/mysql" drive.
Through the above statement, it has to get a connection to the database.
db.SingularTable (true) action phrase will be mentioned later.
2.3 Creating a mapping table structure struct
Corresponding to the structure of the database tables defined struct
For example, here we want to operate a table test table, the table structure is as follows
CREATE TABLE `test` ( `id` bigint(20) NOT NULL, `name` varchar(5) DEFAULT NULL, `age` int(11) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
So we can define the corresponding struct structure is as follows
type Test struct { ID int64 `gorm:"type:bigint(20);column:id;primary_key"` Name string `gorm:"type:varchar(5);column:name"` Age int `gorm:"type:int(11);column:age"` }
After each field marker gorm structure, it can be used to declare the corresponding attributes of the database field.
For example behind the ID field is constrained bigint (20) type, the corresponding list is id, and the primary key field.
In addition, there are richer tag definitions, see the official document: http: //gorm.io/zh_CN/docs/models.html
2.4 CRUD
With three steps in front of the bedding, we're ready to actually write the database operations.
For example, "increase"
test := &Test{ ID:3, Name:"jackie", Age:18, } db.Create(test)
比如"删"
test := &Test{ ID:3, Name:"jackie", Age:18, } db.Delete(test)
比如"改"
test := &Test{ ID: 3, Name: "hello", Age: 18, } db.Model(&test).Update("name", "world")
比如"查"
var testResult Test db.Where("name = ?", "hello").First(&testResult) fmt.Println("result: ", testResult)
如果只是想做个纯粹的CRUDer,掌握上面四步就算是会用gorm了。
如果还想来点花式的,更深入的,继续往下看~~~
3、表名和结构体如何映射
从上面四步,我们只看到在创建DB链接的时候,提供的信息仅仅到数据库,那么gorm是如何做到将表结构和你定义的struct映射起来的呢?
有三种方式可以实现,如果以下三种方式都没有实现,如果你是创建表,则gorm默认会在你定义的struct名后面加上”s“,比如上面就会创建tests表。
3.1 db.SingularTable(true)
通过db.SingularTable(true),gorm会在创建表的时候去掉”s“的后缀
3.2 实现TableName方法
func (Test) TableName() string { return "test" }
TableName方法定义在scope.go的tabler接口中
type tabler interface { TableName() string }
3.3 通过Table API声明
db.Table("test").Where("name = ?", "hello").First(&testResult)
在CRUD前,指明需要操作的表名也是OK的。
4、其他花式操作
下面花式API操作使用表dqm_user_role,对应struct如下
type DqmUserRole struct { ID int64 `gorm:"column:id;primary_key" json:"id"` UserId string `gorm:"column:user_id" json:"user_id"` RoleId string `gorm:"column:role_id" json:"role_id"` CreatedAt time.Time `gorm:"column:created_at" json:"created_at"` UpdatedAt time.Time `gorm:"column:updated_at" json:"updated_at"` }
表中初始数据如下
以下API均亲测可用
First
var dqmUserRole DqmUserRole // 按照主键顺序的第一条记录 db.First(&dqmUserRole) fmt.Println("roleId: ", dqmUserRole.RoleId)
Last
var dqmUserRole1 DqmUserRole // 按照主键顺序的最后一条记录 db.Last(&dqmUserRole1) fmt.Println("roleId: ", dqmUserRole1.RoleId)
Find
var dqmUserRoels []DqmUserRole // 所有记录 db.Find(&dqmUserRoels) fmt.Println("dqmUserRoles: ", dqmUserRoels)
Where
var dqmUserRole3 DqmUserRole // 根据条件查询得到满足条件的第一条记录 db.Where("role_id = ?", "2").First(&dqmUserRole3) fmt.Println("where roleId: ", dqmUserRole3.RoleId) var dqmUserRoles4 []DqmUserRole // 根据条件查询得到满足条件的所有记录 db.Where("user_id = ?", "1").Find(&dqmUserRoles4) fmt.Println("where dqmUserRoles: ", dqmUserRoles4) var dqmUserRole5 []DqmUserRole // like模糊查询 db.Where("role_id like ?", "%2").Find(&dqmUserRole5) fmt.Println("where dqmUserRoles: ", dqmUserRole5) var dqmUserRole6 []DqmUserRole db.Where("updated_at > ?", "2019-02-08 18:08:27").Find(&dqmUserRole6) fmt.Println("where dqmUserRoles: ", dqmUserRole6) var dqmUserRole7 DqmUserRole // struct结构查询条件 db.Where(&DqmUserRole{RoleId: "1,2", UserId: "1"}).First(&dqmUserRole7) fmt.Println("where dqmUserRole: ", dqmUserRole7) var dqmUserRole8 DqmUserRole // map结构查询条件 db.Where(map[string]interface{}{"role_id": "1,2", "user_id": "1"}).Find(&dqmUserRole8) fmt.Println("where dqmUserRole: ", dqmUserRole8)
Not
var dqmUserRole9 DqmUserRole db.Not([]int64{1}).First(&dqmUserRole9) fmt.Println("not dqmUserRole: ", dqmUserRole9)
Or
var dqmUserRole10 []DqmUserRole db.Where(&DqmUserRole{RoleId: "1,2"}).Or(map[string]interface{}{"user_id": "2"}).Find(&dqmUserRole10) fmt.Println("or dqmUserRoles: ", dqmUserRole10)
FirstOrInit和Attrs
var dqmUserRole11 DqmUserRole // 查不到该条记录,则使用attrs值替换 db.Where("user_id = ?", "0").Attrs("role_id", "12").FirstOrInit(&dqmUserRole11) fmt.Println("after FirstOrInit: ", dqmUserRole11) var dqmUserRole12 DqmUserRole // 查到记录,则使用数据库中的值 db.Where("user_id = ?", "1").Attrs("role_id", "2").FirstOrInit(&dqmUserRole12) fmt.Println("after FirstOrInit: ", dqmUserRole12)
FirstOrInit和Assign
var dqmUserRole13 DqmUserRole // 不管是否找到对应记录,使用Assign值替代查询到的值 db.Where("role_id = ?", "1,2").Assign(DqmUserRole{UserId: "15"}).FirstOrInit(&dqmUserRole13) fmt.Println("assign dqmUserRole: ", dqmUserRole13)
FirstOrCreate
var dqmUserRole14 DqmUserRole // 如果记录存在则返回结果,如果不存在则创建 db.Where(&DqmUserRole{UserId: "3", RoleId: "3"}).FirstOrCreate(&dqmUserRole14) fmt.Println("firstOrCreate dqmUserRole: ", dqmUserRole14)
Order
var dqmUserRole16 []DqmUserRole db.Order("user_id desc").Find(&dqmUserRole16) // 注意这里的order要在find前面,否则不生效 fmt.Println("order dqmUserRoles: ", dqmUserRole16)
Limit和Offset
var dqmUserRole18 []DqmUserRole db.Limit(10).Offset(2).Find(&dqmUserRole18) // 如果只有offset没有limit则不会生效 fmt.Println("offset dqmUserRoles: ", dqmUserRole18)
Scan
type Result struct { Id int64 } var results []Result db.Select("id").Where("user_id in (?)", []string{"1", "2"}).Find(&dqmUserRole20).Scan(&results) fmt.Println("ids: ", results)
支持执行原生sql
var dqmUserRole24 []DqmUserRole db.Exec("select * from dqm_user_role").Find(&dqmUserRole24) fmt.Println("sql dqmUserRole: ", dqmUserRole24)
事务
tx := db.Begin() defer func() { if r := recover(); r != nil { tx.Rollback() } if err != nil { tx.Rollback() } else { tx.Commit() } }() if err = tx.Create(&DqmUserRole{UserId: "8", RoleId: "8"}).Error; err != nil { //tx.Rollback() //return } if err = tx.Create(&DqmUserRole{UserId: "9", RoleId: "9"}).Error; err != nil { //tx.Rollback() //return }
错误处理
var dqmUserRole25 DqmUserRole err = db.Where("role_id = ?", 54321).First(&dqmUserRole25).Error if err == gorm.ErrRecordNotFound { fmt.Println("ErrRecordNotFound, record not found") } else { fmt.Println("err: ", err) } fmt.Println("err dqmUserRole: ", dqmUserRole25)
5、总结
gorm作为一款orm库,几乎满足了一个CRUDer的一切想象。实现灵活,花样繁多。
有了gorm,就不需要再在代码中维护sql语句了。
后面有时间会再看看gorm的实现,作为国人开源的第一个orm库,目前star已经超过15k,值得深入学习下。
如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!如果您想持续关注我的文章,请扫描二维码,关注JackieZheng的微信公众号,我会将我的文章推送给您,并和您一起分享我日常阅读过的优质文章。