【Golang】基於beego/orm實現相同表結構不同表名的分表方法實現

Mr.YF發表於2021-11-22

一、背景

  在業務場景開發的過程中, 隨著資料量的增加,相同表結構不同表名的分表策略是常用的方案選擇之一。如下以golang做為後端業務開發,嘗試修改beego的orm庫做一個相同表結構不同表名的分表實現。

二、orm相同表結構不同表名的修改邏輯

 

 

 

三、orm分表對比

不分表程式碼使用 分表程式碼使用

o := orm.NewOrm()
user := User{Name: "slene"}
// insert
id, err := o.Insert(&user)
o := orm.NewOrm()
user := User{Name: "slene"}

// set table name to `user_1`
o.ShardingTable(
    func(tableName string) string {
        return tableName + "_1"
    },
)

// insert
id, err := o.Insert(&user)

o := orm.NewOrm()
user := User{Name: "slene"}

// update
user.Name = "astaxie"
num, err := o.Update(&user)

  

o := orm.NewOrm()
user := User{Name: "slene"}

// set table name to `user_1`
o.ShardingTable(
    func(tableName string) string {
        return tableName + "_1"
    },
)

// update
user.Name = "astaxie"
num, err := o.Update(&user)

  

o := orm.NewOrm()
user := User{id: 1}


// select
o.QueryTable(user).One(&user)
o := orm.NewOrm()
user := User{id: 1}

// set table name to `user_1`
o.ShardingTable(
    func(tableName string) string {
        return tableName + "_1"
    },
)

// select
o.QueryTable(user).Offset(offset).Limit(limit).One(&user)

// select id, name from user_1 where id=1 limit 0,1

o := orm.NewOrm()
user := User{id: 1}


// delete
o.Delete(user)

// delete from user_1 where id=1
o := orm.NewOrm()
user := User{id: 1}

// set table name to `user_1`
o.ShardingTable(
    func(tableName string) string {
        return tableName + "_1"
    },
)

// delete
o.Delete(user)

// delete from user_1 where id=1

從如上的CURD中,我們可以看到如下一段實時修改表名的程式碼

// set table name to `user_1`
o.ShardingTable(
    func(tableName string) string {
        return tableName + "_1"
    },
)

 我們一步步分析一下orm是如何實現表名的實時修改。

四、分表實現分析

 4.1 修改程式碼檔案:https://github.com/gityf/orm/blob/master/orm/types.go

// Ormer define the orm interface
type Ormer interface {
// ...
   // set sharding table in time for different table name with same struct.
// ormer.ShardingTable(
// func(tableName string) string {
// return tableName + "_" + tableNameSuffix
// },
// )
ShardingTable(func(string) string)
}

 修改types.go的Ormer介面,增加分表的函式,引數是一個獲取分表的函式,即每一個分表的表名的設定是一個orm例項。通過orm.NewOrm()建立。

4.2 修改程式碼檔案:https://github.com/gityf/orm/blob/master/orm/orm.go

修改orm.go檔案,給結構orm增加如下兩個分表相關的函式

type orm struct {
alias *alias
db dbQuerier
isTx bool
sharding func(string) string
shardingTable func(string) string
}

有了如上的sharding函式,我們只要在建立orm時,實時的設定這個sharding函式,通過函式獲取新表名。

在函式NewOrm中給新建立的

o := new(orm)

設定一個分表函式如下

// switch to another registered database driver by given name.
func (o *orm) Using(name string) error {
	// ...
	if al, ok := dataBaseCache.get(name); ok {
		o.sharding = func(table string) string {
			if o.shardingTable == nil {
				return table
			}
			return o.shardingTable(table)
		}
	}
	// ...
}

orm結構體有了分表函式的設定,我們需要給orm的成員dbQuerier增加分表函式如下

o.db = &DB{
RWMutex: al.DB.RWMutex,
DB: al.DB.DB,
stmtDecorators: al.DB.stmtDecorators,
sharding: o.sharding,
}

 4.3 修改程式碼檔案:https://github.com/gityf/orm/blob/master/orm/db_alias.go

DB是dbQuerier介面的一個實現,對DB結構體的實現增加分表函式

func (d *DB) Sharding(table string) string {
return d.sharding(table)
}

 4.4 修改程式碼檔案:https://github.com/gityf/orm/blob/master/orm/db.go

對db程式碼檔案中的dbBase的CURD中的sql生成時,增加如下實時修改表名的實現 q.Sharding(mi.table)

// create insert sql preparation statement object.
func (d *dbBase) PrepareInsert(q dbQuerier, mi *modelInfo) (stmtQuerier, string, error) {
Q := d.ins.TableQuote()

// ...
   query := fmt.Sprintf("INSERT INTO %s%s%s (%s%s%s) VALUES (%s)", Q, q.Sharding(mi.table), Q, Q, columns, Q, qmarks)
// ...
}

其他的orm轉sql的通過dbQuerier的q.Sharding(mi.table)獲取表名

 

增加orm相同表結果不同表名的程式碼實現:https://github.com/gityf/orm

 

祝玩的開心~

相關文章