文章首发于公众号【程序员读书】,欢迎关注。
GORM是一个非常优秀的Golang数据库ORM库,支持MySQL, PostgreSQL, SQlite, SQL Server等数据库,目前在Github有接近2.8万个star,足见其优秀与受欢迎的程度。
database/sql
database/sql库是Go内置的用于操作数据库的标准库,在使用Go开发需要操作数据库的项目时,在不引入第三方库的情况下,可以完成对数据库的操作,下面我们通过一个示例来了解一下:
packagemainimport("database/sql""fmt"_"github.com/go-sql-driver/mysql")//操作数据库的对象vardb*sql.DB//数据表模型typeUserstruct{IDintNamestringAgeint}funcmain(){varerrerror//打开数据库连接db,err=sql.Open("mysql","root:123456@tcp(localhost:3306)/test?charset=utf8&parseTime=True&loc=Local")iferr!=nil{panic(err)}iferr=db.Ping();err!=nil{panic(err)}deferdb.Close()//关闭数据库ifInsert(&User{ID:1,Name:"aaaaaa",Age:20})>0{fmt.Println("用户1写入成功")}ifInsert(&User{ID:2,Name:"bbbbbb",Age:21})>0{fmt.Println("用户2写入成功")}//查询单条数据u:=QueryOne(1)fmt.Println(u.ID,u.Name,u.Age)//查询全表数据fmt.Println(QueryAll())//更新ifUpdate(&User{ID:1,Name:"cccccc",Age:30})>0{fmt.Println("用户1信息更新成功")}fmt.Println(QueryOne(1))//删除ifDelete(1){fmt.Println("用户1删除成功")}ifDelete(2){fmt.Println("用户2删除成功")}fmt.Println(QueryOne(1))fmt.Println(QueryOne(2))}funcQueryAll()[]*User{rows,_:=db.Query("SELECT*FROMusers")deferrows.Close()varusers[]*Userforrows.Next(){varuser=&User{}_=rows.Scan(&user.ID,&user.Name,&user.Age)users=append(users,user)}returnusers}funcQueryOne(idint)*User{rows,_:=db.Query("SELECT*FROMusersWHEREid=?",id)deferrows.Close()varuser*Userforrows.Next(){user=&User{}_=rows.Scan(&user.ID,&user.Name,&user.Age)}returnuser}funcDelete(idint)bool{//删rsDelete,err:=db.Exec("DELETEFROMusersWHEREid=?",id)iferr!=nil{returnfalse}n,err:=rsDelete.RowsAffected()iferr!=nil{returnfalse}returnn>0}funcUpdate(user*User)int64{//改rsUpdate,err:=db.Exec("UPDATEusersSETname=?,age=?WHEREid=?",user.Name,user.Age,user.ID)iferr!=nil{return0}n,err:=rsUpdate.RowsAffected()iferr!=nil{return0}returnn}funcInsert(user*User)int64{//增rsInsert,err:=db.Exec("INSERTINTOusersvalues(?,?,?)",user.ID,user.Name,user.Age)iferr!=nil{return0}n,err:=rsInsert.RowsAffected()iferr!=nil{return0}returnn}
从上面的例子中,我们可以看出使用database/sql标准库操作数据库有两个缺点:
不能将模型映对为数据表的操作,需要自己写SQL语句
不能将查询结果集映射到数据模型中,需要自己遍历
对于小项目来说,全部自己写SQL和自己遍历查询结果集,也是可以接受的,但如果是大项目的话,上面两个问题会导致项目越来越难维护。
这时候,使用ORM库可以帮我们完美解决上述的问题,而GORM无疑是首选。
GORM
GORM是一个对Go开发者非常友好的ORM库,上手非常简单,在GORM的官网文档上,我们可以看见其列出了GORM的以下特性:
关联 (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特性非常之多,我们也将在《Golang GORM实战》这个系列中一起学习,慢慢探究与学习GORM的功能与特性,掌握GORM的使用及其原理。
GORM安装与其第三方库安装方式是一样的,非常简单:
安装gorm库
goget-ugorm.io/gorm
安装对应数据库的驱动
#sqlitegoget-ugorm.io/driver/sqlite#mysqlgoget-ugorm.io/driver/mysql#postgresgoget-ugorm.io/driver/postgres#sqlservergoget-ugorm.io/driver/sqlserver
根据你想要访问的数据库,安装对应的驱动即可。
其实如果你细心留意的话,在上面使用database/sql的例子中,也需要安装驱动,在上面的例子中,你可以看下面的代码:
import("database/sql""fmt"_"github.com/go-sql-driver/mysql")
其中github.com/go-sql-driver/MySQL
库便是使用database/sql库访问mysql的驱动。
驱动层才是直接帮我们去访问的数据库的地方,而gorm库和database/sql这两个库只是在驱动层之上再封装一层,提供统一访问层,这样之后如果我们想更换数据库,比如从mysql切换到sqlserver,只需要改下引入的驱动库,而不是修改任何操作数据库的代码,访问层、驱动层与数据库,如下图所示:
我们将上面的示例用GROM重写一次,如下:
packagemainimport("fmt""gorm.io/driver/mysql""gorm.io/gorm")typeUserstruct{IDintNamestringAgeint}funcmain(){dsn:="root:123456@tcp(127.0.0.1:3306)/test?charset=utf8mb4&parseTime=True&loc=Local"db,err:=gorm.Open(mysql.Open(dsn),&gorm.Config{})//打开数据库连接iferr!=nil{panic(err)}DB,_:=db.DB()deferDB.Close()//在函数执行完成后关闭数据库句柄//新增rsOne:=db.Create(&User{ID:1,Name:"aaaaaaaaaa",Age:32})ifrsOne.RowsAffected>0{fmt.Println("用户1创建成功")}rsTwo:=db.Create(&User{ID:2,Name:"bbbbb",Age:32})ifrsTwo.RowsAffected>0{fmt.Println("用户2创建成功")}//查询varu1Userdb.Find(&u1,"id=?",1)fmt.Println(u1)//批量查询varusers[]Userdb.Find(&users)fmt.Println(users)//修改u1.Name="11111111"rsSave:=db.Save(u1)ifrsSave.RowsAffected>0{fmt.Println("用户创建成功")}//修改后查询数据是否已经变化db.Find(&u1,"id=?",4)fmt.Println(u1)//删除rsDelete:=db.Delete(u1)ifrsDelete.RowsAffected>0{fmt.Println("用户删除成功")}}
小结
本篇是《Golang GORM实战》的第一篇文章,我们对比了database/sql与GROM的使用,知道了database/sql的局限性,也清楚GORM的便利性,既然GORM对于我们数据库应用如此便利,那么就有必要在后续中更加深入地学习,因此更多的关于GORM库的知识,笔者也会这个系列中持续更新,欢迎学习,文章不正确的地方,也欢迎指正,先行感谢!