欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

基础配置篇:gorm的使用,数据库的连接和配置以及数据库操作

程序员文章站 2022-07-05 19:54:57
gorm是一个Golang写的,开发人员友好的ORM库。前面配置章节我们已经使用gorm对我们设计的mysql数据库进行了连接。这一节我们再讲讲怎么配置gorm。gorm支持多种数据库连接,目前官方列出来的支持库有:MySQL, PostgreSQL, SQLite, SQL Server 四种数据库连接。在我们要开发的博客网站中,我们选择使用 MySQL 来作为后端数据库。数据库连接连接MySQL数据库,需要引入 gorm 和mysql两个包:import ( "gorm.io/driver/...

gorm是一个Golang写的,开发人员友好的ORM库。前面配置章节我们已经使用gorm对我们设计的mysql数据库进行了连接。这一节我们再讲讲怎么配置gorm。

gorm支持多种数据库连接,目前官方列出来的支持库有:MySQL, PostgreSQL, SQLite, SQL Server 四种数据库连接。在我们要开发的博客网站中,我们选择使用 MySQL 来作为后端数据库。

数据库连接

连接MySQL数据库,需要引入 gorm 和mysql两个包:

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

同时连接mysql需要使用tcp套接字符串来连接,因此需要先构建套接字符串:

dsn := "user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})

这一句的意思是用户名:密码@tcp(数据库ip或域名:端口)/数据库名称?charset=数据库编码&parseTime=True&loc=Local。为了让数据库可以支持emoji,也就是微信聊天里的表情符号,比如????,我们需要将charset设置为utf8mb4。当然只在这里设置是不够的,还需要在设计数据库表的时候,将表编码和字符串字段的编码都设置为utf8mb4才可以支持4字节的utf8编码。

mysql.Config{} 和 gorm.Config{} 还支持更多的详细配置,这里先不深入去介绍,初步学习不用一下子就把所有的东西都学完,一下子很难记住那么多,后面需要用到的再去根据需求来使用其中的配置功能。

为了让mysql可以更好的工作,往往,我们还需要再设置一下给连接对象设置空闲时的最大连接数、设置与数据库的最大打开连接数,每一个连接的生命周期等信息。

  sqlDB, err := db.DB()
	if err != nil {
		return err
	}
	sqlDB.SetMaxIdleConns(1000)
	sqlDB.SetMaxOpenConns(100000)
	sqlDB.SetConnMaxLifetime(-1)
  • db.DB() 是获得db连接对象
  • SetMaxIdleConns 是设置空闲时的最大连接数
  • SetMaxOpenConns 设置与数据库的最大打开连接数
  • SetConnMaxLifetime 每一个连接的生命周期等信息

这几个配置在数据库大量读写的时候,非常有用,可以保证在大量并发读写的时候,数据库依然可以正常工作。

自动迁移表

gorm还有一个强大的功能,就是自动迁移表功能。启用自动迁移模式可以保持mysql表更新到最新。

上一节我们已经创建好了5个表的模型,并且提到了可以使用 AutoMigrate 函数来实现自动迁移,现在我们将它们添加为自动迁移模式。我们重新打开config/config.go,在InitDB()函数中添加上下面的代码:

db.AutoMigrate(&model.Admin{}, &model.Article{}, &model.ArticleData{}, &model.Attachment{}, &model.Category{})

添加完成后的InitDB()函数为:

func InitDB(setting *mysqlConfig) error {
	var db *gorm.DB
	var err error
	url := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local",
		setting.User, setting.Password, setting.Host, setting.Port, setting.Database)
	setting.Url = url
	db, err = gorm.Open(mysql.Open(url), &gorm.Config{})
	if err != nil {
		return err
	}

	sqlDB, err := db.DB()
	if err != nil {
		return err
	}

	sqlDB.SetMaxIdleConns(1000)
	sqlDB.SetMaxOpenConns(100000)
	sqlDB.SetConnMaxLifetime(-1)

	db.AutoMigrate(&model.Admin{}, &model.Article{}, &model.ArticleData{}, &model.Attachment{}, &model.Category{})

	DB = db

	return nil
}

OK,到这里只要我们每次运行这个项目,他都会先执行自动迁移,来保证数据库表的字段更新到最新。

写入数据

上一节,我们这是定义了模型结构体,还没对它进行读写操作。为了方便,我们给每一个模型都添加一个Save() 函数,来统一管理他们的创建和更新数据操作:

admin.go

func (admin *Admin) Save(db *gorm.DB) error {
	if admin.Id == 0 {
		admin.CreatedTime = time.Now().Unix()
	}
	admin.UpdatedTime = time.Now().Unix()

	if err := db.Save(admin).Error; err != nil {
		return err
	}

	return nil
}

Save()函数接受一个*gorm.DB 的指针,并返回一个error错误。我们必须传入 db *gorm.DB 是因为我们这里不能直接使用config.go 下的DB变量,如果我们在这里直接使用config.go 的DB变量的话,就会造成循环依赖的问题,golang是不允许循环依赖的。返回error错误是为了验证是否执行成功,当执行成功的时候,返回值为nil,执行失败的时候,返回值是失败的原因。

Save()函数是Admin模型的内部方法,这个方法操作的是Admin的指针,也就是说这里的admin已经是一个指针了,我们使用db.Save(admin)的时候,就不能再使用指针引用比如写成db.Save(&admin)是错误的,将会导致无法插入和更新数据。

category.go

func (category *Category) Save(db *gorm.DB) error {
	if category.Id == 0 {
		category.CreatedTime = time.Now().Unix()
	}
	category.UpdatedTime = time.Now().Unix()

	if err := db.Save(category).Error; err != nil {
		return err
	}

	return nil
}

Save()函数在执行Save保存的时候,需要判断下是新建还是更新,我们通过Id值来判断,如果值为零,则认为是插入,所以我们需要给 CreatedTime 赋值为当前的时间戳,同时每次 Save我们都认为是一次更新操作,因此还需要给 UpdatedTime 赋值为当前时间戳,来说明这个数据是这个时候进行了更新操作。

article.go

func (article *Article) Save(db *gorm.DB) error {
	if article.Id == 0 {
		article.CreatedTime = time.Now().Unix()
	}
	article.UpdatedTime = time.Now().Unix()

	if err := db.Save(article).Error; err != nil {
		return err
	}

	return nil
}

articles表这里我们进行数据保存的时候,并没有看到我们定义的article_data表的插入和更新操作。那是因为gorm内部会自动根据它们的外键关系处理这一个插入、更新操作。因为我们的Article模型里面定义了ArticleData字段,它是一个一对一的关系。

attachment.go

func (attachment *Attachment) Save(db *gorm.DB) error {
	if attachment.Id == 0 {
		attachment.CreatedTime = time.Now().Unix()
	}
	attachment.UpdatedTime = time.Now().Unix()

	if err := db.Save(attachment).Error; err != nil {
		return err
	}

	attachment.GetThumb()

	return nil
}

func (attachment *Attachment) GetThumb() {
	//如果是一个远程地址,则缩略图和原图地址一致
	if strings.HasPrefix(attachment.FileLocation, "http") {
		attachment.Logo = attachment.FileLocation
		attachment.Thumb = attachment.FileLocation
	} else {
		pfx := "/uploads/"
		attachment.Logo = pfx + attachment.FileLocation
		paths, fileName := filepath.Split(attachment.FileLocation)
		attachment.Thumb = pfx + paths + "thumb_" + fileName
	}
}

Attachment 模型的Save操作,我们还定义了GetThumb() 函数,GetThumb() 函数也是Attachment模型的内部方法,它将自动根据我们定义的上传路径,和展示路径,组织Logo、Thumb字段的显示数据,因为*Attachment是一个指针,我们执行了Save操作后,可以通过指针直接修改attachment变量的值,因此,我们在Save()执行保存后,调用 attachment.GetThumb() 可以立即处理好Logo、Thumb字段的数据。

至此,我们就可以对每一个模型使用Save()函数来保存数据了,Save()函数内部会自动判断该数据是插入还是更新数据,然后执行插入和更新的操作。

相关阅读:
《基础配置篇:gorm的使用,数据库的连接和配置以及数据库操作》

本文地址:https://blog.csdn.net/no_reg/article/details/111028740