在 Go 项目中使用gorm如何实现分表读写?

57 min read

在 Go 项目中使用 gorm 实现分表读写可以通过以下两种方式实现:

  1. 使用 gorm 的钩子函数

Gorm 的钩子函数可以在执行 CRUD 操作前或后执行自定义的代码。我们可以使用钩子函数来自动将数据分散到多个表中。

具体实现方法如下:

// 定义分表结构体和钩子函数
type TableA struct {
    gorm.Model
    Name string
}

func (TableA) TableName() string {
    now := time.Now()
    month := now.Month()
    year := now.Year()
    return fmt.Sprintf("table_a_%d_%d", year, month)
}

func (a *TableA) BeforeSave() (err error) {
    // 执行特定逻辑,例如更改表名
    a.TableName()
    return
}

// 数据库初始化
func Init() {
    db, err := gorm.Open(mysql.Open("dsn"), &gorm.Config{})
    if err != nil {
        panic(err)
    }

    // 自动迁移分表结构体
    db.AutoMigrate(&TableA{})
    // 注册钩子函数
    db.Callback().Create().Before("gorm:before_create").Register("split_table", BeforeCreate)
}

func BeforeCreate(db *gorm.DB) {
    if table, ok := db.Statement.Model.(*TableA); ok {
        // 执行特定逻辑,例如为表中的数据生成分表表名
        table.TableName()
    }
}

在此例子中,BeforeCreate 钩子函数被注册到 Create 钩子函数中,并在写入新记录之前自动为数据库模型对象生成分表表名。

  1. 手动创建多个实例

虽然第一种方法的性能更好,但是手动创建多个实例可以提供更多的灵活性,这在某些情况下是必要的。

// 根据表名称创建数据库模型
func CreateTableA(tableName string) *gorm.DB {
    db, _ := gorm.Open(mysql.Open("dsn"), &gorm.Config{})
    db.Table(tableName).AutoMigrate(&TableA{})
    return db
}

// 写入表A
func WriteTableA(name string) {
    tableName := "table_a_" + time.Now().Format("2006_01")
    db := CreateTableA(tableName)

    tableA := &TableA{Name: name}
    db.Create(tableA)
}

// 读取表A
func ReadTableA(id int) {
    tableName := "table_a_" + time.Now().Format("2006_01")
    db := CreateTableA(tableName)

    var tableA TableA
    db.First(&tableA, id)
}

在此示例中,CreateTableA 函数使用指定的表名创建数据库模型,并自动迁移到该表中。WriteTableA 和 ReadTableA 函数使用 CreateTableA 函数动态创建数据库模型以读取或写入表 A。