GORM核心原理
2026/1/15大约 6 分钟GORM原理源码分析
GORM 核心原理
一、GORM 架构概述
1.1 整体架构
1.2 核心组件
| 组件 | 说明 |
|---|---|
| DB | 数据库连接和配置 |
| Statement | SQL 语句构建器 |
| Callback | 钩子函数链 |
| Dialector | 数据库方言适配 |
| Schema | 模型元数据 |
| Clause | SQL 子句构建 |
二、DB 结构
2.1 核心结构体
// gorm.DB 核心结构
type DB struct {
*Config // 配置
Error error // 错误
RowsAffected int64 // 影响行数
Statement *Statement // SQL 语句
clone int // 克隆标记
}
// Config 配置
type Config struct {
Dialector // 数据库方言
ConnPool ConnPool // 连接池
Logger logger.Interface // 日志
NamingStrategy schema.Namer // 命名策略
Callbacks *callbacks // 回调函数
// ...
}2.2 链式调用原理
// 每次调用都会克隆 DB 实例
func (db *DB) Where(query interface{}, args ...interface{}) *DB {
tx := db.getInstance() // 克隆
tx.Statement.AddClause(clause.Where{
Exprs: tx.Statement.BuildCondition(query, args...),
})
return tx
}
// getInstance 克隆机制
func (db *DB) getInstance() *DB {
if db.clone > 0 {
tx := &DB{Config: db.Config, Error: db.Error}
tx.Statement = &Statement{
DB: tx,
ConnPool: db.Statement.ConnPool,
Context: db.Statement.Context,
Clauses: map[string]clause.Clause{},
}
return tx
}
return db
}为什么要克隆?
- 保证线程安全
- 支持链式调用
- 每个查询独立的 Statement
三、Statement 构建
3.1 Statement 结构
type Statement struct {
*DB
TableExpr *clause.Expr
Table string
Model interface{}
Dest interface{}
Clauses map[string]clause.Clause // SQL 子句
BuildClauses []string // 构建顺序
SQL strings.Builder // 最终 SQL
Vars []interface{} // 参数
// ...
}3.2 Clause 子句系统
// 子句接口
type Clause struct {
Name string
BeforeExpression Expression
AfterNameExpression Expression
AfterExpression Expression
Expression Expression
Builder ClauseBuilder
}
// 常见子句
// SELECT、FROM、WHERE、ORDER BY、LIMIT、OFFSET、JOIN 等3.3 SQL 构建流程
3.4 示例:Where 子句构建
// 添加 Where 条件
func (stmt *Statement) AddClause(v clause.Interface) {
if optimizer, ok := v.(clause.ClauseBuilder); ok {
optimizer.Build(stmt)
}
c, ok := stmt.Clauses[v.Name()]
if !ok {
c.Name = v.Name()
}
v.MergeClause(&c)
stmt.Clauses[v.Name()] = c
}
// Where 子句
type Where struct {
Exprs []Expression
}
func (where Where) Build(builder Builder) {
for idx, expr := range where.Exprs {
if idx > 0 {
builder.WriteString(" AND ")
}
expr.Build(builder)
}
}四、Callback 回调机制
4.1 回调链结构
type callbacks struct {
processors map[string]*processor // 各操作的处理器
}
type processor struct {
db *DB
fns []func(*DB) // 回调函数列表
callbacks []*callback
}
type callback struct {
name string
before string
after string
remove bool
replace bool
match func(*DB) bool
handler func(*DB)
}4.2 默认回调链
4.3 回调执行流程
// 执行回调链
func (p *processor) Execute(db *DB) *DB {
// 编译回调(只执行一次)
if p.fns == nil {
p.compile()
}
// 依次执行回调
for _, fn := range p.fns {
fn(db)
if db.Error != nil {
break
}
}
return db
}
// Create 操作的默认回调
func RegisterDefaultCallbacks(db *DB, config *Config) {
createCallback := db.Callback().Create()
createCallback.Register("gorm:begin_transaction", BeginTransaction)
createCallback.Register("gorm:before_create", BeforeCreate)
createCallback.Register("gorm:save_before_associations", SaveBeforeAssociations)
createCallback.Register("gorm:create", Create)
createCallback.Register("gorm:save_after_associations", SaveAfterAssociations)
createCallback.Register("gorm:after_create", AfterCreate)
createCallback.Register("gorm:commit_or_rollback_transaction", CommitOrRollbackTransaction)
}4.4 自定义回调
// 注册自定义回调
db.Callback().Create().Before("gorm:create").Register("my_plugin:before_create", func(db *gorm.DB) {
// 自定义逻辑
if db.Statement.Schema != nil {
// 设置默认值等
}
})五、Schema 模型解析
5.1 Schema 结构
type Schema struct {
Name string
ModelType reflect.Type
Table string
PrimaryFields []*Field
PrimaryFieldDBNames []string
Fields []*Field
FieldsByName map[string]*Field
FieldsByDBName map[string]*Field
Relationships Relationships
// ...
}
type Field struct {
Name string
DBName string
BindNames []string
DataType DataType
GORMDataType DataType
PrimaryKey bool
AutoIncrement bool
Creatable bool
Updatable bool
// ...
}5.2 模型解析流程
5.3 标签解析
// 解析 gorm 标签
func ParseTagSetting(str string, sep byte) map[string]string {
settings := map[string]string{}
names := strings.Split(str, string(sep))
for i := 0; i < len(names); i++ {
j := i
if len(names[j]) > 0 {
for ; i < len(names) && names[i][len(names[i])-1] == '\\'; i++ {
names[i] = names[i][:len(names[i])-1] + string(sep) + names[i+1]
}
}
values := strings.Split(names[j], ":")
k := strings.TrimSpace(strings.ToUpper(values[0]))
if len(values) >= 2 {
settings[k] = strings.Join(values[1:], ":")
} else if k != "" {
settings[k] = k
}
}
return settings
}
// 示例:解析 `gorm:"primaryKey;size:100;not null"`
// 结果:{"PRIMARYKEY": "PRIMARYKEY", "SIZE": "100", "NOT NULL": "NOT NULL"}六、Dialector 方言系统
6.1 Dialector 接口
type Dialector interface {
Name() string
Initialize(*DB) error
Migrator(db *DB) Migrator
DataTypeOf(*schema.Field) string
DefaultValueOf(*schema.Field) clause.Expression
BindVarTo(writer clause.Writer, stmt *Statement, v interface{})
QuoteTo(clause.Writer, string)
Explain(sql string, vars ...interface{}) string
}6.2 MySQL 方言实现
type Dialector struct {
*Config
}
func (dialector Dialector) Name() string {
return "mysql"
}
func (dialector Dialector) DataTypeOf(field *schema.Field) string {
switch field.DataType {
case schema.Bool:
return "boolean"
case schema.Int, schema.Uint:
return dialector.getSchemaIntAndUnitType(field)
case schema.Float:
return dialector.getSchemaFloatType(field)
case schema.String:
return dialector.getSchemaStringType(field)
case schema.Time:
return dialector.getSchemaTimeType(field)
case schema.Bytes:
return dialector.getSchemaBytesType(field)
}
return string(field.DataType)
}七、连接池管理
7.1 连接池接口
type ConnPool interface {
PrepareContext(ctx context.Context, query string) (*sql.Stmt, error)
ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)
QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)
QueryRowContext(ctx context.Context, query string, args ...interface{}) *sql.Row
}7.2 连接池配置
sqlDB, _ := db.DB()
// 最大空闲连接数
sqlDB.SetMaxIdleConns(10)
// 最大打开连接数
sqlDB.SetMaxOpenConns(100)
// 连接最大生命周期
sqlDB.SetConnMaxLifetime(time.Hour)
// 连接最大空闲时间
sqlDB.SetConnMaxIdleTime(10 * time.Minute)7.3 连接获取流程
八、预编译语句
8.1 启用预编译
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
PrepareStmt: true, // 启用预编译
})8.2 预编译原理
type PreparedStmtDB struct {
Stmts map[string]*Stmt
PreparedSQL []string
Mux *sync.RWMutex
ConnPool
}
func (db *PreparedStmtDB) prepare(ctx context.Context, conn ConnPool, query string) (*Stmt, error) {
db.Mux.RLock()
if stmt, ok := db.Stmts[query]; ok {
db.Mux.RUnlock()
return stmt, nil
}
db.Mux.RUnlock()
// 创建预编译语句
db.Mux.Lock()
defer db.Mux.Unlock()
stmt, err := conn.PrepareContext(ctx, query)
if err == nil {
db.Stmts[query] = &Stmt{Stmt: stmt, Transaction: false}
db.PreparedSQL = append(db.PreparedSQL, query)
}
return db.Stmts[query], err
}九、事务实现
9.1 事务结构
// 开启事务
func (db *DB) Begin(opts ...*sql.TxOptions) *DB {
var (
tx *DB
opt *sql.TxOptions
)
if len(opts) > 0 {
opt = opts[0]
}
tx = db.getInstance()
tx.Statement.ConnPool, tx.Error = db.ConnPool.BeginTx(tx.Statement.Context, opt)
return tx
}
// 提交事务
func (db *DB) Commit() *DB {
if committer, ok := db.Statement.ConnPool.(TxCommitter); ok {
db.Error = committer.Commit()
}
return db
}
// 回滚事务
func (db *DB) Rollback() *DB {
if committer, ok := db.Statement.ConnPool.(TxCommitter); ok {
db.Error = committer.Rollback()
}
return db
}9.2 自动事务
func (db *DB) Transaction(fc func(tx *DB) error, opts ...*sql.TxOptions) error {
tx := db.Begin(opts...)
if tx.Error != nil {
return tx.Error
}
defer func() {
if r := recover(); r != nil {
tx.Rollback()
panic(r)
}
}()
if err := fc(tx); err != nil {
tx.Rollback()
return err
}
return tx.Commit().Error
}