Gorm小技巧: 如何优雅地创建多个相同的表

背景

因为需要bitfinex抓取各种历史交易信息。为了实现可扩展与便于数据管理,在数据架构设计方面满足下面的需求:

  1. 不同的交易对的交易数据放到不同的表上。

方案

方案1

编写sql,通过多条sql语句创建多个不同名字的表。

优点: 1. 理解简单,最容易的方案

缺点:

  1. 如果修改表名称、调整表结构、调整索引,需要重新写sql,如果在线上部署,需要到多台机器上部署与执行,加大出错的概率

  2. 需要额外维护表名称

  3. 不利于docker部署,部署业务sql建立相应表

总之,最容易的方案,确实最难维护的方案。

方案2

方案1种种不足,让我这个懒人实在不感兴趣。要追求优雅的实现方案。所以就发现下面的方案。

type User struct {
    Name      string
    Pwd       string
    tableName string
}

func (u *User) TableName() string {
    
    return u.tableName
}

看完上面的代码,大家应该会立即明白:原来只需要对表结构对应的结构体定义一种方法 TableName(),就可以实现。

一个十分简单示例代码如下:

package main

import (
    "fmt"

    _ "github.com/go-sql-driver/mysql"
    "github.com/jinzhu/gorm"
)

type User struct {
    Name      string
    Pwd       string
    tableName string
}

func (u *User) TableName() string {
    // custom table name, this is default
    return u.tableName
}

func main() {
    db, err := gorm.Open("mysql", "root:@/wallet_development?charset=utf8&parseTime=True&loc=Local")
    if err != nil {
        fmt.Println(err)
        return
    }
    defer db.Close()
    db.AutoMigrate(&User{tableName: "user1"})
    db.AutoMigrate(&User{tableName: "user2"})

    db.Create(&User{tableName: "user1", Name: "n1", Pwd: "p1"})
    db.Create(&User{tableName: "user2", Name: "n2", Pwd: "p2"})
}

优点:

  1. 不需要写sql语句

  2. docker部署不依赖sql先执行

  3. 调整表相关信息,只需要修改代表,重新部署即可

缺点:

  1. 暂时没有发现,你若发现请告诉我。

gorm实现代码

gorm中定义了针对表结构定义了接口TableName(),具体可以看gorm源码

type tabler interface {
    TableName() string
}

type dbTabler interface {
    TableName(*DB) string
}

接口TableName()应用代码如下:

// TableName get model's table name
func (s *ModelStruct) TableName(db *DB) string {
    if s.defaultTableName == "" && db != nil && s.ModelType != nil {
        // Set default table name
        if tabler, ok := reflect.New(s.ModelType).Interface().(tabler); ok {
            s.defaultTableName = tabler.TableName()
        } else {
            tableName := ToDBName(s.ModelType.Name())
            if db == nil || !db.parent.singularTable {
                tableName = inflection.Plural(tableName)
            }
            s.defaultTableName = tableName
        }
    }

    return DefaultTableNameHandler(db, s.defaultTableName)
}

说明

上面方案二,大概看一下,发现没有分享,所以写了下来,希望能够大家能够用上(小发现,还是太有用途)。

(end)

Share Comments
comments powered by Disqus