您现在的位置是:首页 >学无止境 >Golang使用mysql结合gorm框架作为持久化存储中间件网站首页学无止境
Golang使用mysql结合gorm框架作为持久化存储中间件
简介Golang使用mysql结合gorm框架作为持久化存储中间件
背景
项目中其他模块需要MySQL数据库的访问接口,需要一个可靠且高效的数据库连接机制来支持这些功能。为了简化数据库连接管理和提高应用性能,采用了GORM(Go语言的对象关系映射库)来实现数据库交互。
需求
需求分析
-
单一实例:确保在整个应用程序生命周期内仅初始化一次数据库连接,并提供一个全局访问点来获取这个连接。这有助于节省资源并避免重复建立连接带来的性能损耗。
-
延迟初始化(Lazy Initialization):数据库连接应在首次使用时进行初始化,而不是在程序启动时立即初始化,以提高应用启动速度和减少不必要的资源占用。
-
配置管理:支持通过外部配置文件动态设置数据库连接参数,如用户名、密码、主机地址、端口号、数据库名称等信息,以便于根据不同环境(开发、测试、生产)灵活调整。
-
连接池配置:
- 设置最大空闲连接数(MaxIdleConns),优化数据库连接的使用效率。
- 设置最大打开连接数(MaxOpenConns),限制同时可以使用的数据库连接数量,防止过度占用数据库资源。
- 设置连接的最大存活时间(ConnMaxLifetime),保证数据库连接的新鲜度和稳定性。
-
错误处理:当数据库连接失败或初始化过程中出现错误时,应抛出异常(panic),以中断程序执行,防止后续逻辑基于错误状态继续运行。
-
资源释放:提供一种机制来关闭数据库连接,确保在应用程序结束时正确释放所占用的资源。
-
并发安全:考虑到多线程环境下对数据库连接的并发访问需求,解决方案必须保证线程安全性,避免竞态条件等问题。
实现细节对应需求
-
单一实例:
- 使用了全局变量
db存储唯一的数据库连接实例。 sync.Once类型的dbOnce确保openDB函数只会被执行一次。
- 使用了全局变量
-
延迟初始化:
GetDB函数利用dbOnce.Do(openDB)实现了延迟加载,只有当第一次调用该函数时才会触发数据库连接的初始化。
-
配置管理:
config.GetGlobalConfig().DbConfig用于从外部配置文件中读取数据库相关的配置信息。
-
连接池配置:
- 在成功建立数据库连接后,通过
sqlDB.SetMaxIdleConns、sqlDB.SetMaxOpenConns和sqlDB.SetConnMaxLifetime方法设置了连接池的相关参数。
- 在成功建立数据库连接后,通过
-
错误处理:
- 当
gorm.Open返回错误或者尝试获取原生数据库连接失败时,会引发panic,阻止程序继续运行。
- 当
-
资源释放:
- 提供了
CloseDB函数,允许手动关闭数据库连接。
- 提供了
-
并发安全:
sync.Once确保了在多线程环境中数据库连接的初始化是线程安全的,避免了多个goroutine同时尝试初始化数据库连接的问题。
设计模式——单例模式
单例模式(Singleton Pattern) 是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来访问这个实例。单例模式通常用于管理共享资源的应用场景中,例如数据库连接、配置设置、日志记录等。
在Go语言中,实现单例模式通常需要解决两个问题:
- 确保只有一个实例:通过某种机制保证该类只能被实例化一次。
- 提供全局访问点:允许程序中的任何地方都能方便地访问这个唯一的实例。
单例模式的作用:
- 资源节约:通过确保整个应用程序生命周期内只有一个数据库连接实例,减少了资源消耗。
- 简化访问:提供了全局访问点 GetDB(),使得任何地方都可以方便地获取到这个唯一的数据库连接实例。
- 一致性:所有的数据库操作都基于同一个连接池进行,保证了数据的一致性和操作的安全性。
代码实现
package db
import (
"fmt"
"sync"
"time"
"github.com/Isaac033/simpleTok/usersvr/config"
"github.com/Isaac033/simpleTok/usersvr/log"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
var (
// db 是一个包级别的变量,用于保存唯一的单例对象,单例对象为gorm.DB
db *gorm.DB
// dbonce 是一个用于确保初始化操作只执行一次的 sync. Once 对象
dbOnce sync.Once
)
// openDB 连接数据库
// 该函数根据全局配置获取数据库连接信息,并尝试建立连接
// 此函数在初始化数据库连接时会进行panic处理,如果连接失败,将终止程序运行
func openDB() {
// 获取数据库配置
dbConfig := config.GetGlobalConfig().DbConfig
// 根据配置信息构造数据库连接字符串
connArgs := fmt.Sprintf("%s:%s@(%s:%s)/%s?charset=utf8&parseTime=True&loc=Local", dbConfig.Username,
dbConfig.Password, dbConfig.Host, dbConfig.Port, dbConfig.Database)
// 记录数据库连接信息,便于调试
log.Info("mdb addr:" + connArgs)
// 尝试连接数据库
var err error
db, err = gorm.Open(mysql.Open(connArgs), &gorm.Config{})
if err != nil {
// 如果连接失败,抛出panic
panic("failed to connect database")
}
// 获取数据库连接的原始接口,用于设置连接池参数
sqlDB, err := db.DB()
if err != nil {
// 如果获取数据库连接出错,抛出panic
panic("fetch db connection err:" + err.Error())
}
// _ = db.AutoMigrate(&repository.User{})
// 设置数据库连接池参数
sqlDB.SetMaxIdleConns(dbConfig.MaxIdleConn) // 设置最大空闲连接
sqlDB.SetMaxOpenConns(dbConfig.MaxOpenConn) // 设置最大打开的连接
sqlDB.SetConnMaxLifetime(time.Duration(dbConfig.MaxIdleTime * int64(time.Second))) // 设置空闲时间为(s)
}
// GetDB 获取数据库连接
// 该函数确保在并发环境下只打开一个数据库连接,并返回该连接实例
func GetDB() *gorm.DB {
// 利用sync.Once确保openDB只被执行一次
dbOnce.Do(openDB)
// 返回数据库连接实例
return db
}
// CloseDB 关闭数据库连接
// 在程序结束或者不需要数据库连接时,调用该函数释放数据库资源
func CloseDB() {
if db != nil {
// 获取数据库连接的原始接口
sqlDB, err := db.DB()
if err != nil {
// 如果获取数据库连接出错,抛出panic
panic("fetch db connection err:" + err.Error())
}
// 关闭数据库连接
sqlDB.Close()
}
}
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。





QT多线程的5种用法,通过使用线程解决UI主界面的耗时操作代码,防止界面卡死。...
U8W/U8W-Mini使用与常见问题解决
stm32使用HAL库配置串口中断收发数据(保姆级教程)
分享几个国内免费的ChatGPT镜像网址(亲测有效)
Allegro16.6差分等长设置及走线总结