gorm 配置数据库

目录

介绍

GORM 是 Go 语言中最流行的 ORM(对象关系映射)库之一,基于数据库操作的封装,提供类似 Django ORM / SQLAlchemy 的开发体验。

特性 描述
支持多种数据库 MySQL、PostgreSQL、SQLite、SQL Server、ClickHouse 等
自动迁移 自动根据 struct 生成数据库表结构
CRUD 操作简洁 简洁直观的增删查改接口
支持事务 内置事务管理
预加载 一行代码加载关联数据(Preload)
钩子函数 提供 BeforeSave、AfterCreate 等生命周期钩子
软删除 提供内置软删除支持
自定义 SQL 可执行原生 SQL 或复杂查询
迁移、索引 支持复合索引、唯一索引等设置
go get -u gorm.io/gorm
go get -u gorm.io/driver/mysql

配置数据库

一般来说,关于数据库的配置 我喜欢放在 infra/* 这个文件夹下

这里以 pg 为例

pg_connection.go

package infra

import (
	"fmt"
	"time"

	"gin-api-template/utils"

	"gorm.io/driver/postgres"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
)

var DB *gorm.DB //定义一个全局变量 DB,用于保存数据库连接句柄。可供全局调用。

// InitPG 初始化 PostgreSQL 连接
func InitPG() {
	config := utils.AppConfig
	if config == nil {
		utils.LogError("Config not loaded")
		return
	}

	// 构建数据库连接字符串
	dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%s sslmode=disable TimeZone=Asia/Shanghai",
		config.DBHost,
		config.DBUser,
		config.DBPassword,
		config.DBName,
		config.DBPort,
	)

	// 配置 GORM
	gormConfig := &gorm.Config{}

	// 根据环境设置日志级别,开发模式下显示 SQL 日志,生产模式下静默。
	if utils.IsDevelopment() {
		gormConfig.Logger = logger.Default.LogMode(logger.Info)
		utils.LogInfo("PostgreSQL debug mode enabled")
	} else {
		gormConfig.Logger = logger.Default.LogMode(logger.Silent)
	}

	// 连接数据库
	var err error
	DB, err = gorm.Open(postgres.Open(dsn), gormConfig)
	if err != nil {
		utils.LogError("Failed to connect to PostgreSQL: " + err.Error())
		panic(err)
	}

	// 配置连接池
	sqlDB, err := DB.DB()
	if err != nil {
		utils.LogError("Failed to get PostgreSQL instance: " + err.Error())
		panic(err)
	}

	// 设置连接池参数
	sqlDB.SetMaxIdleConns(10)
	sqlDB.SetMaxOpenConns(100)
	sqlDB.SetConnMaxLifetime(time.Hour) //  每个连接的最大生命周期(如过期回收)

	utils.LogInfo("PostgreSQL connected successfully")
}

// GetDB 获取数据库实例
func GetDB() *gorm.DB {
	return DB
}

// ClosePG 关闭数据库连接
func ClosePG() {
	if DB != nil {
		sqlDB, err := DB.DB()
		if err != nil {
			utils.LogError("Failed to get PostgreSQL instance for closing: " + err.Error())
			return
		}

		if err := sqlDB.Close(); err != nil {
			utils.LogError("Failed to close PostgreSQL: " + err.Error())
		} else {
			utils.LogInfo("PostgreSQL connection closed")
		}
	}
}

在 main.go

func main() {
	// 1. 加载配置
	config := utils.LoadConfig()

	// 2. 初始化 PostgreSQL
	infra.InitPG()
	defer infra.ClosePG()
}

GetDB

func GetDB() *gorm.DB {
	return DB
}

这是一个全局访问数据库实例的 Getter 函数,它的作用很简单:

让你在项目中任何地方通过调用 infra.GetDB() 获取一个 *gorm.DB 实例,从而操作数据库。

  • ✅ 数据库连接在 InitPG() 初始化时创建
  • ❌ GetDB() 不会重复建立连接,它只是返回之前初始化好的连接指针
  • ❌ 它也不会自动释放连接
问题 回答
GetDB() 会不会新建连接? 不会,它只是返回初始化后的 *gorm.DB 实例。
GetDB() 会不会释放连接? 不会,连接释放由 GORM 内部连接池自动管理或由 ClosePG() 完成。
如果不主动关闭会有问题吗? 一般不会,因为连接池会回收,但优雅关闭应用时应调用 ClosePG()。
多个请求并发使用 GetDB() 安全么? 是安全的,GORM 是并发安全的,底层连接池会复用连接。

GORM 的 *gorm.DB 实例是线程安全的,不会持有数据库连接本身,只有执行 SQL 时才从连接池中临时借用连接,执行完立即归还。

db := infra.GetDB()
db.Find(&users)

它的实际行为如下:

  1. db := GetDB():只是获取一个 *gorm.DB 对象,不涉及任何连接。
  2. db.Find(&users):
    • 这一步 GORM 内部会调用 sql.DB.Conn(ctx) 或 sql.DB.QueryContext(ctx);
    • 从连接池借一个连接;
    • 执行 SQL;
    • 自动关闭 rows,释放连接,连接归还连接池 ✅
rows, err := db.Raw("SELECT * FROM users").Rows()
defer rows.Close()  // 如果忘记写这句,连接就不会释放!!
场景 是否占用连接
GetDB() ❌ 不占用连接
db.Find()、db.First() 等 ✅ 使用连接 → 自动释放
SSE/流式接口 + 查询前置 ✅ 查询连接已释放,SSE 是纯内存流
使用 Rows() 没有手动 Close() ⚠️ 会占用连接池

点赞一下

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦