package db import ( "fmt" "github.com/fwhezfwhez/cmap" "github.com/fwhezfwhez/errorx" "github.com/garyburd/redigo/redis" "github.com/jinzhu/gorm" "strings" "time" ) var existTable = cmap.NewMapV2(nil, 2, 15*time.Second) type table interface { TableName() string SourceTableName() string } var tmpl = `create table ${table_name} (like ${source_table_name} including all);` func MustHaveTable( engine *gorm.DB, // 提供数据查表是否创建,以及创表句柄 t table, // 提供表的源表名,和分表名 f func() redis.Conn, // 提供获取conn的方法,用于分布式环境创建唯一) ) (bool, error) { created, exist := existTable.Get(t.TableName()) if exist && created == true { return true, nil } if engine.HasTable(t) { existTable.SetEx(t.TableName(), true, 60) return true, nil } // 15秒内的并发下,只会有一条,走进创建语句 if !once(f(), fmt.Sprintf("%s:auto_create_%s:%s", config.Node.AppName, config.Node.Mode, t.TableName()), 15) { return true, nil } sql := strings.ReplaceAll(tmpl, "${table_name}", t.TableName()) sql = strings.ReplaceAll(sql, "${source_table_name}", t.SourceTableName()) // do create if e := engine.Exec(sql).Error; e != nil { return false, errorx.Wrap(e) } existTable.SetEx(t.TableName(), true, 60) return true, nil }