GORM是一个非常优秀的Golang数据库ORM库,支持MySQL, PostgreSQL, SQlite, SQL Server等数据库
database/sql
database/sql库是Go内置的用于操作数据库的标准库,在使用Go开发需要操作数据库的项目时,在不引入第三方库的情况下,可以完成对数据库的操作
package main
import (
"database/sql"
"fmt"
)
/*
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
age INT NOT NULL
);
*/
import (
_ "github.com/go-sql-driver/mysql" //驱动
)
// 操作数据库的对象
var db *sql.DB
// User 数据表模型
type User struct {
ID int
Name string
Age int
}
func main() {
var err error
//打开数据库连接
db, err = sql.Open("mysql", "root:123qwe@tcp(localhost:3306)/mysql_db?charset=utf8&parseTime=True&loc=Local")
if err != nil {
panic(err)
}
//验证连接
if err = db.Ping(); err != nil {
panic(err)
}
defer db.Close() //关闭数据库
if Insert(&User{Name: "aaaaaa", Age: 20}) > 0 {
fmt.Println("用户写入成功")
}
if Insert(&User{Name: "bbbbbb", Age: 21}) > 0 {
fmt.Println("用户写入成功")
}
//查询全表数据
uSlice := QueryAll()
for _, us := range uSlice {
fmt.Println(us.ID, us.Name, us.Age)
}
//查询单条数据
u := QueryOne(uSlice[0].ID)
if u != nil {
fmt.Println(u.ID, u.Name, u.Age)
}
//更新
if Update(&User{ID: uSlice[0].ID, Name: "cccccc", Age: 30}) > 0 {
fmt.Printf("用户%v信息更新成功\n", uSlice[0].ID)
}
if user := QueryOne(uSlice[0].ID); user != nil {
fmt.Println(user.ID, user.Name, user.Age)
}
//删除
if Delete(uSlice[0].ID) {
fmt.Printf("用户%v删除成功\n", uSlice[0].ID)
}
if Delete(uSlice[1].ID) {
fmt.Printf("用户%v删除成功\n", uSlice[1].ID)
}
fmt.Println(QueryOne(uSlice[0].ID))
fmt.Println(QueryOne(uSlice[1].ID))
}
func QueryAll() []*User {
rows, _ := db.Query("SELECT * FROM users")
defer rows.Close()
var users []*User
for rows.Next() {
var user = &User{}
err := rows.Scan(&user.ID, &user.Name, &user.Age)
if err != nil {
panic(err)
}
users = append(users, user) //放到User指针切片
}
return users
}
func QueryOne(id int) *User {
rows, _ := db.Query("SELECT * FROM users WHERE id = ?", id)
defer rows.Close() //避免资源泄露
var user *User
for rows.Next() {
user = &User{}
// 将结果扫描到结构体中
err := rows.Scan(&user.ID, &user.Name, &user.Age)
if err != nil {
panic(err)
}
}
return user
}
func Delete(id int) bool {
//删
rsDelete, err := db.Exec("DELETE FROM users WHERE id = ?", id)
if err != nil {
return false
}
n, err := rsDelete.RowsAffected()
if err != nil {
return false
}
return n > 0
}
func Update(user *User) int64 {
//改
rsUpdate, err := db.Exec("UPDATE users SET name = ?,age = ? WHERE id = ?", user.Name, user.Age, user.ID)
if err != nil {
return 0
}
n, err := rsUpdate.RowsAffected()
if err != nil {
return 0
}
return n
}
func Insert(user *User) int64 {
//增
rsInsert, err := db.Exec("INSERT INTO users values(?,?,?)", user.ID, user.Name, user.Age)
if err != nil {
return 0
}
n, err := rsInsert.RowsAffected() //执行 SQL 语句后影响的行数
if err != nil {
return 0
}
return n
}
使用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库
go get -u gorm.io/gorm
安装对应数据库的驱动
# sqlite
go get -u gorm.io/driver/sqlite
# mysql
go get -u gorm.io/driver/mysql
# postgres
go get -u gorm.io/driver/postgres
# sqlserver
go get -u gorm.io/driver/sqlserver
驱动层才是直接帮我们去访问的数据库的地方,而gorm库和database/sql这两个库只是在驱动层之上再封装一层,提供统一访问层,这样之后如果我们想更换数据库,比如从mysql切换到sqlserver,只需要改下引入的驱动库,而不是修改任何操作数据库的代码,访问层、驱动层与数据库
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
/*
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
age INT NOT NULL
);
*/
type User struct {
ID int
Name string
Age int
}
func main() {
dsn := "root:123qwe@tcp(127.0.0.1:3306)/mysql_db?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{}) //打开数据库连接
if err != nil {
panic(err)
}
DB, err := db.DB()
if err != nil {
panic(err)
}
defer DB.Close() //在函数执行完成后关闭数据库句柄
//新增
rsOne := db.Create(&User{Name: "aaaaaaaaaa", Age: 30})
if rsOne.RowsAffected > 0 {
fmt.Println("用户创建成功")
}
rsTwo := db.Create(&User{Name: "bbbbbbbbbb", Age: 32})
if rsTwo.RowsAffected > 0 {
fmt.Println("用户创建成功")
}
//批量查询
var users []User
db.Find(&users)
for _, user := range users {
fmt.Println(user)
}
//查询
var u User
db.Find(&u, "id = ?", users[0].ID)
fmt.Println(u)
//修改
u.Name = "2222222222"
rsSave := db.Save(u)
if rsSave.RowsAffected > 0 {
fmt.Println("用户修改成功")
}
//修改后查询数据是否已经变化
db.Find(&u, "id = ?", users[0].ID)
fmt.Println(u)
//删除
rsDelete := db.Delete(u)
if rsDelete.RowsAffected > 0 {
fmt.Printf("用户%v删除成功\n", u.ID)
}
//删除
user := db.Delete(users[1])
if user.RowsAffected > 0 {
fmt.Printf("用户%v删除成功\n", users[1].ID)
}
}