您现在的位置是:首页 >学无止境 >Golang使用mysql结合gorm框架作为持久化存储中间件网站首页学无止境

Golang使用mysql结合gorm框架作为持久化存储中间件

Heath033 2026-03-22 12:01:04
简介Golang使用mysql结合gorm框架作为持久化存储中间件

背景

项目中其他模块需要MySQL数据库的访问接口,需要一个可靠且高效的数据库连接机制来支持这些功能。为了简化数据库连接管理和提高应用性能,采用了GORM(Go语言的对象关系映射库)来实现数据库交互。

需求

需求分析

  1. 单一实例:确保在整个应用程序生命周期内仅初始化一次数据库连接,并提供一个全局访问点来获取这个连接。这有助于节省资源并避免重复建立连接带来的性能损耗。

  2. 延迟初始化(Lazy Initialization):数据库连接应在首次使用时进行初始化,而不是在程序启动时立即初始化,以提高应用启动速度和减少不必要的资源占用。

  3. 配置管理:支持通过外部配置文件动态设置数据库连接参数,如用户名、密码、主机地址、端口号、数据库名称等信息,以便于根据不同环境(开发、测试、生产)灵活调整。

  4. 连接池配置

    • 设置最大空闲连接数(MaxIdleConns),优化数据库连接的使用效率。
    • 设置最大打开连接数(MaxOpenConns),限制同时可以使用的数据库连接数量,防止过度占用数据库资源。
    • 设置连接的最大存活时间(ConnMaxLifetime),保证数据库连接的新鲜度和稳定性。
  5. 错误处理:当数据库连接失败或初始化过程中出现错误时,应抛出异常(panic),以中断程序执行,防止后续逻辑基于错误状态继续运行。

  6. 资源释放:提供一种机制来关闭数据库连接,确保在应用程序结束时正确释放所占用的资源。

  7. 并发安全:考虑到多线程环境下对数据库连接的并发访问需求,解决方案必须保证线程安全性,避免竞态条件等问题。

实现细节对应需求

  • 单一实例

    • 使用了全局变量db存储唯一的数据库连接实例。
    • sync.Once类型的dbOnce确保openDB函数只会被执行一次。
  • 延迟初始化

    • GetDB函数利用dbOnce.Do(openDB)实现了延迟加载,只有当第一次调用该函数时才会触发数据库连接的初始化。
  • 配置管理

    • config.GetGlobalConfig().DbConfig用于从外部配置文件中读取数据库相关的配置信息。
  • 连接池配置

    • 在成功建立数据库连接后,通过sqlDB.SetMaxIdleConnssqlDB.SetMaxOpenConnssqlDB.SetConnMaxLifetime方法设置了连接池的相关参数。
  • 错误处理

    • gorm.Open返回错误或者尝试获取原生数据库连接失败时,会引发panic,阻止程序继续运行。
  • 资源释放

    • 提供了CloseDB函数,允许手动关闭数据库连接。
  • 并发安全

    • sync.Once确保了在多线程环境中数据库连接的初始化是线程安全的,避免了多个goroutine同时尝试初始化数据库连接的问题。

设计模式——单例模式

单例模式(Singleton Pattern) 是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来访问这个实例。单例模式通常用于管理共享资源的应用场景中,例如数据库连接、配置设置、日志记录等。

在Go语言中,实现单例模式通常需要解决两个问题:

  1. 确保只有一个实例:通过某种机制保证该类只能被实例化一次。
  2. 提供全局访问点:允许程序中的任何地方都能方便地访问这个唯一的实例。

单例模式的作用:

  • 资源节约:通过确保整个应用程序生命周期内只有一个数据库连接实例,减少了资源消耗。
  • 简化访问:提供了全局访问点 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()
	}
}
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。