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的使用,数据库的连接和配置以及数据库操作》
需要了解更多数据库技术:基础配置篇:gorm的使用,数据库的连接和配置以及数据库操作,都可以关注数据库技术分享栏目—计算机技术网(www.ctvol.com)!
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/dtteaching/812138.html