快速入门go的orm框架-gorm

前言

近期参加青训营学习了下Go语言,本篇是orm框架-gorm的一些快速使用与总结。

所有博客文件目录索引:博客目录索引(持续更新)

博客源码:gitee仓库github仓库

资料

gorm-github地址

gorm的官方文档GORM中文文档

初次接触

原生SQL驱动包进行查询

gorm 操作mysql

数据库表:

-- ----------------------------
-- Table structure for users
-- ----------------------------
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users`  (
  `id` int(11) NOT NULL,
  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of users
-- ----------------------------
INSERT INTO `users` VALUES (1, '琳儿');
INSERT INTO `users` VALUES (2, '长路');
INSERT INTO `users` VALUES (3, '小明');

SET FOREIGN_KEY_CHECKS = 1;

代码:

package main

import (
   "database/sql"  //导入sql驱动
   "fmt"
   _ "github.com/go-sql-driver/mysql"
   "log"
)

type User struct {
	id int64
	name string
}

func main() {
	//使用driver(指定mysql) + DSN初始化DB连接
	db, err := sql.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/hello")
	//rows, err := db.Query("select id,name from users where id = ?", 1)
	rows, err := db.Query("select id,name from users")
	if err != nil {
		log.Printf("连接异常")
	}
	defer func() {
		err = rows.Close()  //处理完毕,释放连接
	}()
	//定义用户数组
	var users []User
	for rows.Next() {
		var user User
		err := rows.Scan(&user.id, &user.name)
		if err != nil {
			log.Printf("解析有误")
		}
		users = append(users, user)
	}
	fmt.Println(users)

}

image-20220526151758952

实战gorm查询单表所有记录

GORM增删改查gorm普通的增删改查

数据库表:

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for food
-- ----------------------------
DROP TABLE IF EXISTS `food`;
CREATE TABLE `food`  (
  `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增ID,商品Id',
  `name` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '商品名',
  `price` decimal(10, 2) UNSIGNED NOT NULL COMMENT '商品价格',
  `type_id` int(10) UNSIGNED NOT NULL COMMENT '商品类型Id',
  `createtime` datetime(0) NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '创建时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of food
-- ----------------------------
INSERT INTO `food` VALUES (1, 'CHANGLU', 100.00, 125, '2022-05-10 16:01:04');
INSERT INTO `food` VALUES (2, 'LINER', 1000.00, 666, '2022-05-03 16:01:25');

SET FOREIGN_KEY_CHECKS = 1;

代码:

package main

import (
	"fmt"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"log"
	"testing"
	"time"
)

//默认gorm对struct字段名使用Snake Case命名风格转换成mysql表字段名(需要转换成小写字母)
type Food struct {
	Id         int  //表字段名为:id
	Name       string //表字段名为:name
	Price      float64 //表字段名为:price
	TypeId     int  //表字段名为:type_id
	//我们也可以进行自定义对应映射的字段名:字段定义后面使用两个反引号``包裹起来的字符串部分叫做标签定义,这个是golang的基础语法,不同的库会定义不同的标签,有不同的含义
	CreateTime time.Time `gorm:"column:createtime"`  //表字段名为:createtime  //若是数据库中是DateTime,那么对应这里使用time,之后序列化可以进行转换时间日期
}


//创建表默认是这个表名
//设置表名,可以通过给Food struct类型定义 TableName函数,返回一个字符串作为表名
func (v Food) TableName()string  {
	return "food"
}

func Test_gormImpl(t *testing.T)  {
	db, err := connect()
	if err != nil {
		log.Printf("")
	}
	//v2版本中db没有close()方法:https://www.cnblogs.com/chengqiang521/p/15122102.html
	sqlDB, _  := db.DB()
	var foods []Food
	//查询所有的food列表记录
	db.Find(&foods)
	fmt.Println(foods)
	//延时关闭数据库连接
	defer sqlDB.Close()
}

func connect()  (db *gorm.DB, err error)  {
	//配置MySQL连接参数
	username := "root"  //账号
	password := "123456" //密码
	host := "127.0.0.1" //数据库地址,可以是Ip或者域名
	port := 3306 //数据库端口
	Dbname := "hello" //数据库名
	timeout := "10s" //连接超时,10秒
	//拼接下dsn参数, dsn格式可以参考上面的语法,这里使用Sprintf动态拼接dsn参数,因为一般数据库连接参数,我们都是保存在配置文件里面,需要从配置文件加载参数,然后拼接dsn。
	dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8&parseTime=True&loc=Local&timeout=%s", username, password, host, port, Dbname, timeout)
	//连接MYSQL, 获得DB类型实例,用于后面的数据库读写操作。
	db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		return db, err
	}
	return db,nil
}

一、知识点学习

1.1、gorm.Model

type Model struct {
   ID        uint `gorm:"primarykey"`
   CreatedAt time.Time
   UpdatedAt time.Time
   DeletedAt DeletedAt `gorm:"index"`
}

//其中DeletedAt的类型为sql.NullTime
//该属性涉及到之后软删除和硬删除
type DeletedAt sql.NullTime

1.2、CRUD大整合

配套代码:go-gormLearn/***

说明:我们只要建好数据库即可,其他表都可以进行自动生成。

image-20220528200128766

init.go

package db

import (
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
)

var DB *gorm.DB

func Init()  {
	var err error
	DB, err = gorm.Open(mysql.Open("root:123456@tcp(localhost:3306)/hello?charset=utf8&parseTime=True&loc=Local"),
		&gorm.Config{
			PrepareStmt:            true,
			SkipDefaultTransaction: true,
			Logger:logger.Default.LogMode(logger.Info),  //打印执行的sql
		},
	)
	if err != nil {
		panic(err)
	}

	//进行表的创建
	m := DB.Migrator()
	if !m.HasTable(&User{}) {
		if err = m.CreateTable(&User{}); err != nil {
			panic(err)
		}
	}
}

核心的增删改查方法在user.go中:下面的内容都在这个user.go中

package db

import (
	"context"
	"gorm.io/gorm"
)

type User struct {
	gorm.Model
	Name string     `gorm:"type:varchar(32);not null"`
	Password string `gorm:"type:varchar(32);not null"`
}

func (v User) TableName()string  {
	return "user"
}

添加

//创建用户
func CreateUser(ctx context.Context, users []*User) error {
	//INSERT INTO `user` (`created_at`,`updated_at`,`deleted_at`,`name`,`password`) VALUES ('2022-05-28 19:30:45.339','2022-05-28 19:30:45.339',NULL,'changlu','123456'),()
	return DB.WithContext(ctx).Create(users).Error
}

//查询用户(未被软删除的)
func QueryAllUsers(ctx context.Context)([]*User, error)  {
	var users []*User
	//SELECT * FROM `user` WHERE `user`.`deleted_at` IS NULL
	if err := DB.WithContext(ctx).Find(&users).Error; err != nil {
		return nil,err
	}
	return users, nil
}

//查询所有用户(包含软删除的)
func QueryAllIncludeDeletedUsers(ctx context.Context)([]*User, error)  {
	var users []*User
	//SELECT * FROM `user`
	if err := DB.WithContext(ctx).Unscoped().Find(&users).Error; err != nil {
		return nil,err
	}
	return users, nil
}

//只查询软删除用户
func QueryAllDeletedUsers(ctx context.Context)([]*User, error) {
	var users []*User
	//SELECT * FROM `user` WHERE deleted_at <> ''
	if err := DB.WithContext(ctx).Unscoped().Where("deleted_at <> ?", "").Find(&users).Error;err != nil {
		return nil, err
	}
	return users, nil
}

//分页查询
func PageQueryUser(ctx context.Context, pageNo, pageSize int)([]*User, error)  {
	tx := DB.WithContext(nil).Model(&User{})
	//...字段补充  tx.where()...
	var users []*User
	if err := tx.Offset((pageNo - 1) * pageSize).Limit(pageSize).Find(&users).Error; err != nil {
		return nil, err
	}
	return users, nil
}

两种方式修改:①struct更新。(非零不会更新)②select更新。(必更新)

当通过 struct 更新时,GORM 只会更新非零字段。 如果您想确保指定字段被更新,你应该使用 Select 更新选定字段,或使用 map 来完成更新操作:

//修改用户
//方式一:通过struct来进行更新
func UpdateUser(ctx context.Context, user *User) error {
	//UPDATE `user` SET `updated_at`='2022-05-28 19:31:24.468',`name`='changlu111',`password`='12132232' WHERE `user`.`deleted_at` IS NULL AND `id` = 1
	return DB.WithContext(ctx).Model(&user).Select("Name", "Password").Updates(user).Error
}
//方式二:通过map进行更新
func UpdateUser2(ctx context.Context, ID uint, username *string, password *string )error  {
	params := make(map[string]interface{})
	if username != nil {
		params["Name"] = username
	}
	if password != nil {
		params["Password"] = password
	}
	//UPDATE `user` SET `name`='changlu666',`password`='122222',`updated_at`='2022-05-28 19:32:05.675' WHERE id = 1 AND `user`.`deleted_at` IS NULL
	return DB.WithContext(ctx).Model(&User{}).Where("id = ?", ID).Updates(params).Error
}
//恢复软删除
func RecoverUserDeleted(ctx context.Context, ID uint)error  {
	//UPDATE `user` SET `deleted_at`=NULL,`updated_at`='2022-05-28 19:16:19.579' WHERE `ID` = 1
	return DB.WithContext(ctx).Model(&User{}).
				Unscoped(). //针对已软删除的,此时就不会带上`user`.`deleted_at` IS NULL
				Where("ID", ID).Update("deleted_at", nil).Error
}

gorm软删除妙用-充值,软删除恢复,soft delete

//删除用户
//方式一:软删除
func SofeDeleteUser(ctx context.Context, ID uint) error {  //uint指的是无符号整数,其大小根据当前的平台来决定
	//UPDATE `user` SET `deleted_at`='2022-05-28 19:32:30.124' WHERE id = 1 AND `user`.`deleted_at` IS NULL
	return DB.WithContext(ctx).Where("id = ?", ID).Delete(&User{}).Error
}
//方式二:硬删除
func DeleteUser(ctx context.Context, user *User) error {
	//调用Unscoped即可表示硬删除
	//DELETE FROM `user` WHERE `user`.`id` = 1
	return DB.WithContext(ctx).Unscoped().Delete(user).Error
}

main.go:测试方法

package main

import (
	"fmt"
	"go-gormLearn/db"
)

func main()  {
	db.Init()

	//1、创建用户(无需填充gorm.model,即可自动进行插入更新值)
	//users := make([]*db.User, 2)
	//users[0] = &db.User{
	//	Model:    gorm.Model{},
	//	Name:     "changlu",
	//	Password: "123456",
	//}
	//users[1] = &db.User{
	//	Model:    gorm.Model{},
	//	Name:     "test",
	//	Password: "123456",
	//}
	//db.CreateUser(nil, users)
	
	//2、更新用户(会自动更新updatetime)
	//方式一:借助struct
	//u := &db.User{
	//	Model: gorm.Model{
	//		ID: 1,
	//	},
	//	Name:     "changlu111",
	//	Password: "12132232",
	//}
	//db.UpdateUser(nil, u)	//通过!
	//方式二:借助map
	//username := "changlu666"
	//password := "122222"
	//db.UpdateUser2(nil, 1, &username, &password)//通过!
	//恢复软删除
	db.RecoverUserDeleted(nil, 1)

	//3、删除用户
	//3.1、软删除
	//db.SofeDeleteUser(nil, 1)
	//3.2、硬删除
	//db.DeleteUser(nil, &db.User{
	//	Model:    gorm.Model{
	//		ID: 1,
	//	},
	//})

	//4、查询用户
	//4.1、查询所有未软删除用户
	//users, _ := db.QueryAllUsers(nil)
	//for _, user := range users {
	//	fmt.Println(user)
	//}
	//4.2、查询所有用户(包含软删除的)
	//users, _ := db.QueryAllIncludeDeletedUsers(nil)
	//for _, user := range users {
	//	fmt.Println(user)
	//}
	//4.3、只查询软删除的用户
	//users, _ := db.QueryAllDeletedUsers(nil)
	//for _, user := range users {
	//	fmt.Println(user)
	//}
	//4.4、分页查询
	users, _ := db.PageQueryUser(nil, 1, 1)
	for _, user := range users {
		fmt.Println(user)
	}

}

二、性能提升

2.1、基本配置

gorm中文文档—事务

db, err := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{
  ... //配置信息
})

①禁止默认事务:对于写操作(创建、更新、删除),为了确保数据的完整性,GORM 会将它们封装在事务内运行。但这会降低性能,你可以在初始化时禁用这种方式

SkipDefaultTransaction: true,

②缓存预编语句:执行任何 SQL 时都创建并缓存预编译语句,可以提高后续的调用速度

全局模式:

PrepareStmt: true,  //【若是使用hock或者关联创建的时候设置为false】

会话模式:

// 会话模式
tx := db.Session(&Session{PrepareStmt: true})
tx.First(&user, 1)
tx.Find(&users)
tx.Model(&user).Update("Age", 18)

③Prepared Statement与原生sql使用

PrepareStmt: true,

//示例:
db.Raw("select sum(age) from users where role = ?", "admin").Scan(&age)

2.2、常用配置

import (
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

var DB *gorm.DB

func Init()  {
	var err error
	DB, err = gorm.Open(mysql.Open("gorm:gorm@tcp(localhost:3306)/hello?charset=utf8&parseTime=True&loc=Local"),
		&gorm.Config{
			PrepareStmt:            true,  //预编译
			SkipDefaultTransaction: true,  //关闭默认事务
		},
	)
	if err != nil {
		panic(err)
	}
}

三、Migrator

gorm的Migrator是干什么的?

//进行表的创建
m := DB.Migrator()
if !m.HasTable(&User{}) {  //是否存在表
    if err = m.CreateTable(&User{}); err != nil {  //创建表
        panic(err)
    }
}

问题1:为什么设置的结构体的某个字段没有再表中创建?

原因:字段必须为大写,否则无法创建。

type User struct {
	gorm.Model
	Name string     `gorm:"type:varchar(32);not null"`   //使用gorm可以来进行定义字段的类型
	Password string `gorm:"type:varchar(32);not null"`
}

四、其他方面

4.1、执行sql时打印日志

如何让gorm输出执行的sql

1、打印所有的sql

&gorm.Config{
    Logger:logger.Default.LogMode(logger.Info),  //打印执行的sql
},

我是长路,感谢你的耐心阅读。如有问题请指出,我会积极采纳!
欢迎关注我的公众号【长路Java】,分享Java学习文章及相关资料
Q群:851968786 我们可以一起探讨学习
注明:转载可,需要附带上文章链接

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
### 回答1: 在 Go 语言中,最受欢迎的 ORM(Object-Relational Mapping)框架可能是 Gorm。Gorm 是一个简单而强大的 ORM 框架,支持许多数据库,包括 MySQL、PostgreSQL、SQLite 和 SQL Server。它具有高度可配置的查询构建器,允许您使用简单的方法查询数据库。此外,Gorm 还提供了许多有用的功能,如自动迁移、钩子函数和缓存支持。 另一个受欢迎的 Go 语言 ORM 框架是 Beego ORM。Beego ORM 是与 Beego 框架一起使用的 ORM,但也可以单独使用。它提供了简单易用的 API,允许您在 Go 中轻松地操作数据库。Beego ORM 还提供了许多有用的功能,如自动迁移、模型钩子函数和查询构建器支持。 还有许多其他优秀的 Go 语言 ORM 框架,如 SQLBoiler、Xorm 和 buf clean。最终,哪个 ORM 框架最适合您取决于您的需求和喜好。建议您比较多个选项,然后根据您的项目需求选择最合适的 ORM 框架。 ### 回答2: 在Go语言中,有许多流行的ORM(对象关系映射)框架可供选择,而最好用的框架往往会因个人需求而异。然而,其中一个备受推崇的是GORM。 GORM是一个功能强大的Go语言ORM框架,被广泛认可的原因有以下几点: 1. 简单易用:GORM提供了简洁直观的API,使得对数据库的操作变得轻而易举。开发者可以利用GORM实现复杂的数据库查询、插入、更新和删除操作,而无需深入学习SQL语句。 2. 数据库兼容性:GORM支持多种数据库,如MySQL、PostgreSQL、SQLite等,因此具备良好的数据库兼容性。这使得GORM可以适用于各种类型的项目,无论是小型还是大型,无论是简单还是复杂。 3. 数据迁移工具:GORM内置了强大的数据库迁移工具,可以轻松地管理数据库模式的变更。通过简单的命令,开发者可以自动执行数据库迁移脚本,而无需手动操作数据库。 4. 提供事务支持:GORM支持事务处理,使得开发者可以对数据库操作进行原子性处理。通过提供Begin、Commit和Rollback等事务相关的方法,GORM确保了数据的完整性和一致性。 5. 强大的查询构建器:GORM的查询构建器使得开发者可以快速构建复杂的查询语句,包括联接查询、条件筛选、分组、排序等。同时,GORM还支持预加载机制,减少了数据库查询的次数,提高了性能。 总而言之,GORM作为一种功能强大、易用性高、数据库兼容性好的ORM框架,可以帮助开发者更加便捷地操作数据库,提高开发效率和代码质量。因此,GORM可以被认为是Go语言中最好用的ORM框架之一。 ### 回答3: Go语言最好用的ORM框架是GORM。 GORM是一个功能丰富且易于使用的ORM库,提供了非常方便的数据库访问和操作接口,可以与多种数据库系统进行交互。以下是GORM的一些特点: 1. 简单易用:GORM提供了简洁的API和强大的查询功能,使得开发人员可以更轻松地进行数据库操作。 2. 自动迁移:GORM可以自动将Go结构体与数据库表进行映射,并可以根据结构体的变化自动更新数据库表结构,减少了手动迁移的工作。 3. 事务支持:GORM支持事务操作,开发人员可以使用事务来保证数据库操作的一致性和完整性。 4. 关联关系映射:GORM支持一对一、一对多、多对多等关联关系的映射,可以轻松进行复杂的数据查询和操作。 5. 高性能:GORM通过一系列的优化措施,如缓存、批量操作等,提供了较高的性能。 6. 扩展性:GORM提供了丰富的Hook机制,可以方便地在数据库操作中插入自定义逻辑,扩展其功能。 总之,GORM是一个功能全面、易于使用且性能优越的ORM框架,它为Go语言的开发者提供了便捷的数据库操作解决方案,是最好用的ORM框架之一。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

长路 ㅤ   

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值