go-gorm / sharding Goto Github PK
View Code? Open in Web Editor NEWThis project forked from longbridgeapp/gorm-sharding
High performance table sharding plugin for Gorm.
License: MIT License
This project forked from longbridgeapp/gorm-sharding
High performance table sharding plugin for Gorm.
License: MIT License
Recently, I test sharding plugin and try to intergate it in my project. However, it fail the tests when I run the example in https://github.com/go-gorm/sharding/tree/main/examples/order.go
.
The only difference is the database driver. I replace postgres
to mysql
.
enviroment:
OS: WSL1 for Win10
Go: go version go1.17.6 linux/amd64
Package:
gorm.io/driver/mysql v1.2.3
gorm.io/gorm v1.22.5
gorm.io/sharding v0.4.0
The following is the error message:
2022/02/21 09:19:34 ~/main.go:67 Error 1146: Table 'gorm.orders' doesn't exist
[19.048ms] [rows:0] INSERT INTO `orders` (`user_id`,`product_id`) VALUES (2,0)
Error 1146: Table 'gorm.orders' doesn't exist
and the code:
// this record will insert to orders_02
err = db.Create(&Order{UserID: 2}).Error
if err != nil {
fmt.Println(err)
}
```go
Apparently, the sharding policy does not work. It try to insert new record in `orders` not `orders_2`.
Is sharding's support for mysql not in place yet?
When I try to use sharding to drive mysql , I get an unexpected error
in gorm.io/gorm/finisher_api.go:547
Transaction
, nested transaction need to check if connPool fit TxCommitter:
BEGIN
has been called, so use SAVEPOINT
insteadBEGIN
.However, sharding
plugin impl BeginTx
/ Commit
/ Rollback
in same struct
. So it can fit TxCommitter
interface without BEGIN
call. The nested transaction won't work.
ConnPool
struct CANNOT impl TxBeginner
and TxCommitter
interface in the same time. When BeginTx
is called, different struct need to be returned.
type Order struct {
ID int64 `gorm:"primarykey"`
UserID int64
ProductID int64
}
for i := 0; i < 64; i += 1 {
table := fmt.Sprintf("orders_%02d", i)
db.Exec(`DROP TABLE IF EXISTS ` + table)
db.Exec(`CREATE TABLE ` + table + ` (id int PRIMARY KEY,user_id int,product_id int)`)
}
middleware := sharding.Register(sharding.Config{
ShardingKey: "user_id",
NumberOfShards: 64,
PrimaryKeyGenerator: sharding.PKSnowflake,
}, "orders")
err = db.Use(middleware)
if err != nil {
panic(err)
}
err = db.Create(&Order{UserID: 2}).Error
if err != nil {
fmt.Println(err)
}
err = db.Create(&Order{UserID: 3}).Error
if err != nil {
fmt.Println(err)
}
err = db.Create(&Order{UserID: 4}).Error
if err != nil {
fmt.Println(err)
}
[13.420ms] [rows:0] CREATE TABLE orders_00 (id int PRIMARY KEY,user_id int,product_id int)
...
[13.420ms] [rows:0] CREATE TABLE orders_63 (id int PRIMARY KEY,user_id int,product_id int)
2022/01/27 23:41:07 ./gorm.go:144 Error 1146: Table 'orders' doesn't exist
[0.567ms] [rows:0] INSERT INTO `orders` (`user_id`,`product_id`) VALUES (2,0)
Error 1146: Table 'orders' doesn't exist
stmt.Parse
will change its own value, it will cause some bugs.
https://github.com/go-gorm/gorm/blob/master/migrator/migrator.go#L48
https://github.com/go-gorm/sharding/blob/main/sharding.go#L113
func (s *Sharding) compile() error {
...
// stmt := &gorm.Statement{DB: s.DB}
stmt := s.DB.Statement
if err := stmt.Parse(table); err == nil {
s.configs[stmt.Table] = s._config
} else {
return err
}
...
}
I think the code stmt := &gorm.Statement{DB: s.DB}
should be used instead, but it is commented, is this necessary?
the features in documentation - (https://gorm.io/docs/sharding.html#Features )say it is possible but did not find any documentation about the same.
ShardingAlgorithm: func(columnValue interface{}) (suffix string, err error) {
if id, ok := columnValue.(uint); ok {
return fmt.Sprintf("_%02d", id%shardingNum), nil
}
return "", fmt.Errorf("invalid column value type")
}
and just migrate table {table_name}_00
TableName()
, and just like thisfunc (d *dataobject) TableName() string {
return fmt.Sprintf("table_name_%02d", d.ID%shardingNum)
}
and just migrate table {table_name}_00
and didnot creat any new table
code:
db.Use(sharding.Register(sharding.Config{ ShardingKey: "user_id", NumberOfShards: 64, PrimaryKeyGenerator: sharding.PKSnowflake, }, "orders").Register(sharding.Config{ ShardingKey: "user_id", NumberOfShards: 256, PrimaryKeyGenerator: sharding.PKSnowflake, // This case for show up give notifications, audit_logs table use same sharding rule. }, Notification{}, AuditLog{}))
the second Register function show error below:
*sharding.Register((sharding.Config literal), (model.XXXX literal)).Register undefined (type sharding.Sharding has no field or method
why?
thanks.
I also met this question sharding Error 1054: Unknown column 'ny_order.deleted_at' in 'where clause'
2023/02/19 20:57:18 testing mysql...
=== RUN TestGORM
2023/02/19 20:57:18 /Users/zhengjb/go/src/github.com/zishiguo/playground/main_test.go:13 Error 1054 (42S22): Unknown column 'user_follow.deleted_at' in 'where clause'
[2.526ms] [rows:0] SELECT * FROM `user_follow` WHERE user_id = 79535114761158382 AND `user_follow`.`deleted_at` IS NULL
main_test.go:14: Failed, got error: Error 1054 (42S22): Unknown column 'user_follow.deleted_at' in 'where clause'
--- FAIL: TestGORM (0.00s)
FAIL
Process finished with the exit code 1
not compatible with "gorm.io/plugin/soft_delete" plugins when using mysql
I am using the latest version 0.5.3 of gorm sharding and have encountered two issues with primary keys.
Problem 1: When inserting, a primary key will be generated based on the suffix. My suffix is not a number, which causes the insert to fail (such as line 363 of the sharding.go source code image). The solution comes from rows 357 and 358, but my table primary key is not called "ID" but "order_id". Is there a way to skip the error of row 363.
Question 2: When querying, if there is an "id" field, it must be of type int64, otherwise it will cause an error in line 486. Is there a way to skip this judgment and successfully query
I want to know if there is a way to bypass the limitation of gorm sharing for primary keys that are "ID" and of type int64
In the latest release v0.6.0, the go version requirement in go.mod was upgraded from 1.20 to 1.21.
According to the release note of go 1.21, the go
version in go.mod is now a strict minimum requirement, which means that in order to use this module, users need to upgrade their go version to 1.21. This may cause some concerns, since go 1.21 was just released a month ago.
My question is that could we downgrade the go
version of go.mod?
支持mysql分表么,支持的话可以去掉自动填充主键么
Cannot find NumberOfShards in sharding.Config, PrimaryKeyGenerator in field, and sharding.PKSnowflake property does not exist.
Can you provide the latest examples
I met soft delete question.
order.go doesn't cover soft delete cases.
example can cover soft delete cases.
example can cover soft delete cases.
// BeginTx Implement ConnPoolBeginner.BeginTx
func (pool *ConnPool) BeginTx(ctx context.Context, opt *sql.TxOptions) (gorm.ConnPool, error) {
if basePool, ok := pool.ConnPool.(gorm.ConnPoolBeginner); ok {
return basePool.BeginTx(ctx, opt)
}
return pool, nil
}
For this method, when init with default setting, pool.ConnPool
is actually an sql.DB
struct, which return pool, nil
directly. Transaction is not opened.
Error 1136: Column count doesn't match value count at row 2
mysql create with slice
func (pool ConnPool) QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error) {
ftQuery, stQuery, table, err := pool.sharding.resolve(query, args...)
if err != nil {
return nil, err
}
pool.sharding.querys.Store("last_query", stQuery)
if table != "" {
if r, ok := pool.sharding.configs[table]; ok {
if r.DoubleWrite {
pool.ConnPool.ExecContext(ctx, ftQuery, args...)
}
}
}
return pool.ConnPool.QueryContext(ctx, stQuery, args...)
}
支持分库吗,即将分表分布在多个数据库上
sharding key or id required, and use operator =
user_id use Snowflake id,such as 79535114761158382
md5(user_id)
get first one letter for schema name, then join wkread_users_
, such as wkread_users_a
every database host has two schema, such as wkread_users_2
,wkread_users_3
in the db06
host
first two letters for table name, then join user_
, such as tables user_30
,user_31``user_32``user_33``user_34``user_35``user_36``user_37``user_38``user_39``user_3a``user_3b``user_3c``user_3d``user_3e``user_3f
in the schema wkread_users_3
db05
wkread_users_0
user_00
user_01
...
user_0f
wkread_users_1
user_10
user_11
...
user_1f
db06
wkread_users_2
user_20
user_21
...
user_2f
wkread_users_3
user_30
user_31
...
user_3f
...
db12
wkread_users_e
user_e0
user_e1
...
user_ef
wkread_users_f
user_f0
user_f1
...
user_ff
default:
master:
Name: express
Addr: 10.131.32.124:30001
UserName: root
Password: hhel0315
db05-wkread_users_0:
master:
Name: wkread_users_0
Addr: 10.131.32.124:30005
UserName: root
Password: hhel0315
db05-wkread_users_1:
master:
Name: wkread_users_1
Addr: 10.131.32.124:30005
UserName: root
Password: hhel0315
db06-wkread_users_2:
master:
Name: wkread_users_2
Addr: 10.131.32.124:30006
UserName: root
Password: hhel0315
db06-wkread_users_3:
master:
Name: wkread_users_3
Addr: 10.131.32.124:30006
UserName: root
Password: hhel0315
db07-wkread_users_4:
master:
Name: wkread_users_4
Addr: 10.131.32.124:30007
UserName: root
Password: hhel0315
db07-wkread_users_5:
master:
Name: wkread_users_5
Addr: 10.131.32.124:30007
db08-wkread_users_6:
master:
Name: wkread_users_6
Addr: 10.131.32.124:30008
db08-wkread_users_7:
master:
Name: wkread_users_7
Addr: 10.131.32.124:30008
db09-wkread_users_8:
master:
Name: wkread_users_8
Addr: 10.131.32.124:30009
db09-wkread_users_9:
master:
Name: wkread_users_9
Addr: 10.131.32.124:30009
db10-wkread_users_a:
master:
Name: wkread_users_a
Addr: 10.131.32.124:30010
db10-wkread_users_b:
master:
Name: wkread_users_b
Addr: 10.131.32.124:30010
db11-wkread_users_c:
master:
Name: wkread_users_c
Addr: 10.131.32.124:30011
db11-wkread_users_d:
master:
Name: wkread_users_d
Addr: 10.131.32.124:30011
db12-wkread_users_e:
master:
Name: wkread_users_e
Addr: 10.131.32.124:30012
UserName: root
Password: hhel0315
db12-wkread_users_f:
master:
Name: wkread_users_f
Addr: 10.131.32.124:30012
func NewReadWriteSplits(cm map[string]ReadWriteSplitConfig) (db *gorm.DB) {
defaultConfig := cm["default"]
defaultMasterConfig := defaultConfig.Master
dialector := NewDialectorWithPool(&defaultMasterConfig)
db, err := gorm.Open(dialector, gormConfig(&defaultMasterConfig))
if err != nil {
log.Panicf("database connection failed. database name: %s, err: %+v", defaultMasterConfig.Name, err)
}
db.Set("gorm:table_options", "CHARSET=utf8mb4")
// default
resolver := dbresolver.Register(dbresolver.Config{
Replicas: func(cs []Config) []gorm.Dialector {
var ds []gorm.Dialector
for _, c := range cs {
ds = append(ds, NewDialectorWithPool(&c))
}
return ds
}(defaultConfig.Slaves),
TraceResolverMode: true,
})
// other
for name, c := range cm {
if name == "default" {
break
}
resolver = resolver.Register(dbresolver.Config{
Sources: func(c Config) []gorm.Dialector {
ds := []gorm.Dialector{
NewDialector(&c),
}
return ds
}(c.Master),
Replicas: func(cs []Config) []gorm.Dialector {
var ds []gorm.Dialector
for _, c := range cs {
ds = append(ds, NewDialector(&c))
}
return ds
}(c.Slaves),
TraceResolverMode: true,
}, name).SetMaxOpenConns(c.Master.MaxOpenConn).
SetMaxIdleConns(c.Master.MaxIdleConn).
SetConnMaxLifetime(c.Master.ConnMaxLifeTime).
SetConnMaxIdleTime(c.Master.ConnMaxIdleTime)
}
db.Use(resolver)
return db
}
func (d *repository) GetUser(ctx context.Context, uid int64) (*model.User, error) {
var data model.User
resolverName := data.GetDBResolverName(uid)
db := d.orm.WithContext(ctx).Clauses(dbresolver.Use(string(resolverName)))
err := db.Use(sharding.Register(sharding.Config{
ShardingKey: "id",
NumberOfShards: 16,
PrimaryKeyGenerator: sharding.PKSnowflake,
ShardingAlgorithmByPrimaryKey: func(id int64) (suffix string) {
hashed, _ := utils.Md5(fmt.Sprintf("%d", id))
fmt.Printf("id:%d, hashed:%s\n", id, hashed)
return fmt.Sprintf("_%s", hashed[:2])
},
}, model.User{}))
if err != nil {
return nil, errors.Wrapf(err, "[repo.user] sharding.Register err")
}
err = db.First(&data, uid).Error
if errors.Is(err, ErrNotFound) {
return nil, ErrNotFound
} else if err != nil {
return nil, errors.Wrapf(err, "[repo.user] query db err")
}
return &data, nil
}
2023/02/13 20:13:11 /Users/zhengjb/go/src/gitlab.y5ops.com/jin/hertz_demo/biz/repository/user_repo.go:30 sharding key or id required, and use operator =
[0.141ms] [rows:0] [replica] SELECT * FROM `user` WHERE `user`.`id` = 79535114761158382 ORDER BY `user`.`id` LIMIT 1
Can not db.Use
used when db.Clauses
is used ?
get a user as expected. or how to do as described ?
in project when i use gorm sharding and my SQL contains JOIN, like A.col1, B.col2
the query will fail. the query trys to find the main table instead of sub table
any help ? thanks
比如我想根据主键id 自定义一个路由策略 根据一定的算法把数据路由到对应的数据库或者表 要怎么实现
2023/02/19 21:14:12 testing mysql...
panic: interface conversion: sharding.ShardingMigrator is not migrator.BuildIndexOptionsInterface: missing method BuildIndexOptions
goroutine 1 [running]:
gorm.io/gorm/migrator.Migrator.CreateTable.func1(0x14000484380)
/Users/zhengjb/go/src/github.com/zishiguo/playground/gorm/migrator/migrator.go:247 +0x568
gorm.io/gorm/migrator.Migrator.RunWithValue({{0x0?, 0x14000271500?, {0x105414100?, 0x1400023c000?}}}, {0x105330f80?, 0x1400023c230}, 0x140000e3540)
/Users/zhengjb/go/src/github.com/zishiguo/playground/gorm/migrator/migrator.go:62 +0x13c
gorm.io/gorm/migrator.Migrator.CreateTable({{0x70?, 0x14000271500?, {0x105414100?, 0x1400023c000?}}}, {0x140004803c0?, 0x140004803c0?, 0x0?})
/Users/zhengjb/go/src/github.com/zishiguo/playground/gorm/migrator/migrator.go:198 +0x114
gorm.io/gorm/migrator.Migrator.AutoMigrate({{0x0?, 0x14000270720?, {0x105414100?, 0x1400023c000?}}}, {0x1400021bad0?, 0x105311aa0?, 0x1400023c001?})
/Users/zhengjb/go/src/github.com/zishiguo/playground/gorm/migrator/migrator.go:112 +0x244
gorm.io/sharding.ShardingMigrator.AutoMigrate({{0x105417ca8, 0x14000270690}, 0x140002368f0, {0x105413e40, 0x14000010bd0}}, {0x1400021b770?, 0x0?, 0x0?})
/Users/zhengjb/go/pkg/mod/gorm.io/sharding@v0.5.2/dialector.go:45 +0x308
gorm.io/gorm.(*DB).AutoMigrate(0x140000017a0?, {0x1400021b770, 0x1, 0x1})
/Users/zhengjb/go/src/github.com/zishiguo/playground/gorm/migrator.go:28 +0x44
gorm.io/playground.RunMigrations()
/Users/zhengjb/go/src/github.com/zishiguo/playground/db.go:113 +0x194
gorm.io/playground.init.0()
/Users/zhengjb/go/src/github.com/zishiguo/playground/db.go:37 +0x108
Process finished with the exit code 1
替换原sql, gorm 追踪记录新的sql内容
希望执行分表后生成新的sql记录到日志中,而不是原来的sql。
conn_pool.go
type ConnPool struct {
// db, This is global db instance
sharding *Sharding
gorm.ConnPool
currentDB *gorm.DB // 记录当前的db实例
}
func (pool ConnPool) ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error) {
// ....
pool.sharding.querys.Store("last_query", stQuery)
// 重置sql
oldSqlCap := pool.currentDB.Statement.SQL.Cap()
pool.currentDB.Statement.SQL.Reset()
pool.currentDB.Statement.SQL.Grow(oldSqlCap + 5)
pool.currentDB.Statement.SQL.WriteString(stQuery)
// ...
}
func (pool ConnPool) QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error) {
// ...
pool.sharding.querys.Store("last_query", stQuery)
// 重置sql
oldSqlCap := pool.currentDB.Statement.SQL.Cap()
pool.currentDB.Statement.SQL.Reset()
pool.currentDB.Statement.SQL.Grow(oldSqlCap + 5)
pool.currentDB.Statement.SQL.WriteString(stQuery)
// ...
}
sharding.go
func (s *Sharding) switchConn(db *gorm.DB) {
// Support ignore sharding in some case, like:
// When DoubleWrite is enabled, we need to query database schema
// information by table name during the migration.
if _, ok := db.Get(ShardingIgnoreStoreKey); !ok {
s.ConnPool = &ConnPool{ConnPool: db.Statement.ConnPool, sharding: s, currentDB: db} // 记录当前的db实例
db.Statement.ConnPool = s.ConnPool
}
}
_ = db.Use(sharding.Register(sharding.Config{
ShardingKey: "ymd",
NumberOfShards: 100,
PrimaryKeyGenerator: sharding.PKCustom,
ShardingAlgorithm: func(columnValue any) (suffix string, err error) {
parentId := cast.ToInt(columnValue)
suffix = fmt.Sprintf("_%v", parentId)
return
},
PrimaryKeyGeneratorFn: func(tableIdx int64) int64 {
return 0
},
// This case for show up give notifications, audit_logs table use same sharding rule.
}, ChatMsg{}))
qb.Where(fmt.Sprintf("(MATCH(body) AGAINST('%s'))", req.Key))
can not fond table
sharding.Register func will be get the same plugin name for sharding,so different sharding-key column could not register successfully when invoking db.USE()
The same database has multiple tables with different shardingkey rules
Is it possible to support setting plugins name to solve the problem of different shardingKey rules for multiple tables in the same database?
db.Use(sharding.Register(sharding.Config{
ShardingKey: "user_id",
NumberOfShards: 64,
PrimaryKeyGenerator: sharding.PKSnowflake,
}, "orders").Register(sharding.Config{
ShardingKey: "user_id",
NumberOfShards: 256,
PrimaryKeyGenerator: sharding.PKSnowflake,
// This case for show up give notifications, audit_logs table use same sharding rule.
}, Notification{}, AuditLog{}))
This example won't work since Register return a struct which hasn't implemented the Register
method.
type User struct{
ID int64 `gorm:"column:id;primaryKey"`
UserId int64 `gorm:"column:user_id"`
}
shard, err := sharding.Register(sharding.Config{
ShardingKey: "user_id",
NumberOfShards: 1,
PrimaryKeyGenerator: sharding.PKSnowflake,
ShardingAlgorithm: getShardFn(1),
}, "users"))
if err != nil {
return nil, err
}
if err := db.Use(shard); err != nil {
return nil, err
}
result := db.Create(&user) // pass pointer of data to Create
user.ID // 0
Right now sharding is creating tables under public
schema while we use custom name so it fail when there is no public
already created. Please consider adding support for custom schema names in Postgres.
db.Use(sharding.Register(sharding.Config{
ShardingKey: "user_id",
ShardingAlgorithm: func(value interface{}) (suffix string, err error) {
if uid, ok := value.(int64); ok {
return fmt.Sprintf("_%02d", uid%4), nil
}
return "", errors.New("invalid user_id")
},
PrimaryKeyGenerate: func(tableIdx int64) interface{} {
// use Built in keygen for generate a sequence primary key with table index
return keygen.Next(tableIdx)
}
}, "orders").Register(sharding.Config{
ShardingKey: "user_id",
ShardingAlgorithm: func(value interface{}) (suffix string, err error) {
if uid, ok := value.(int64); ok {
return fmt.Sprintf("_%02d", uid%4), nil
}
return "", errors.New("invalid user_id")
},
PrimaryKeyGenerate: func(tableIdx int64) interface{} {
return uuid.UUID()
}
// This case for show up give notifications, activities table use same sharding rule.
}, Notification{}, Acitivity{}))
Hi,
目前有需求是注册不同类型的shardingkey 切片表, gorm (db.Use()) 如果多次使用相同name的插件会被返回已注册.
请问该如何实现, 谢谢
EnableFullTable
is means double write in to main table for keep all records have a duplication version in main table.
This feature helpful for:
Use go-gorm/sharding in concurrency, occur DATA RACE sometimes on production environment.
The code below may occur DATA RACE:
func (s *Sharding) switchConn(db *gorm.DB) {
// Support ignore sharding in some case, like:
// When DoubleWrite is enabled, we need to query database schema
// information by table name during the migration.
if _, ok := db.Get(ShardingIgnoreStoreKey); !ok {
s.ConnPool = &ConnPool{ConnPool: db.Statement.ConnPool, sharding: s}
db.Statement.ConnPool = s.ConnPool
}
}
Update:
func (s *Sharding) switchConn(db *gorm.DB) {
// Support ignore sharding in some case, like:
// When DoubleWrite is enabled, we need to query database schema
// information by table name during the migration.
if _, ok := db.Get(ShardingIgnoreStoreKey); !ok {
s.mutex.Lock()
if db.Statement.ConnPool != nil {
if _, ok := db.Statement.ConnPool.(ConnPool); !ok {
db.Statement.ConnPool = &ConnPool{ConnPool: db.Statement.ConnPool, sharding: s}
}
}
s.mutex.Unlock()
}
}
Env:
go 1.16
mysql: 5.7.28
sharding: 0.5.2
gorm: 1.24.3
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/sharding"
)
type User struct {
ID int64 `gorm:"column:id;primaryKey"`
UserId int64 `gorm:"column:user_id"`
}
func main() {
dsn := "username:pwd@tcp(host:3306)/database_name?charset=utf8mb4&parseTime=true&loc=Local"
db, _ := gorm.Open(mysql.New(mysql.Config{DSN: dsn}))
shard := sharding.Register(sharding.Config{
ShardingKey: "user_id",
NumberOfShards: 2,
PrimaryKeyGenerator: sharding.PKSnowflake,
}, "users")
db.Use(shard)
user := User{UserId: 42}
err := db.Create(&user).Error // nil
if err != nil {
panic(err)
}
fmt.Println(user.ID) // 0
}
debug code
gorm: callbacks/create.go
Create() {
insertID, err := result.LastInsertId() // 0
insertOk := err == nil && insertID > 0
}
// return 0
func (res *mysqlResult) LastInsertId() (int64, error) {
return res.insertId, nil
}
请问sharding支持mysql吗?有没有demo
I try to modify the example code to test MySQL sharding
But when I use model interface to access, there will be an error
I change it to Table, is OK
I think this issue like #14 ?
my env:
examples/order.go
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"gorm.io/gorm/schema"
"gorm.io/sharding"
)
type Order struct {
ID int64 `gorm:"primarykey"`
UserID int64
ProductID int64
}
func main() {
connection := fmt.Sprintf("test:test@tcp(127.0.0.1:3306)/?parseTime=true")
db, err := gorm.Open(mysql.New(mysql.Config{
DSN: connection,
}), &gorm.Config{
NamingStrategy: schema.NamingStrategy{
SingularTable: true,
},
Logger: logger.Default.LogMode(logger.Silent),
})
if err != nil {
fmt.Println("err", err)
}
db.Exec("USE " + "MyTable")
for i := 0; i < 4; i += 1 {
table := fmt.Sprintf("orders_%d", i)
db.Exec(`DROP TABLE IF EXISTS ` + table)
db.Table(table).AutoMigrate(&Order{})
}
// db.AutoMigrate(&Order{})
middleware := sharding.Register(sharding.Config{
ShardingKey: "user_id",
NumberOfShards: 4,
PrimaryKeyGenerator: sharding.PKSnowflake,
}, "orders")
db.Use(middleware)
// this record will insert to orders_02
// !!!!!!!!!!!!!!!!!! it returm err: Error 1146: Table 'MyTable.order' doesn't exist
// err = db.Create(&Order{UserID: 2}).Error
err = db.Table("orders").Create(&Order{UserID: 2}).Error
if err != nil {
fmt.Println("err1", err)
}
// this record will insert to orders_03
err = db.Exec("INSERT INTO orders(user_id) VALUES(?)", int64(3)).Error
if err != nil {
fmt.Println("err2", err)
}
// this will throw ErrMissingShardingKey error
err = db.Exec("INSERT INTO orders(product_id) VALUES(1)").Error
fmt.Println("err3", err)
// this will redirect query to orders_02
var orders []Order
// !!!!!!!!!!!!!!!!!! it returm err: Error 1146: Table 'MyTable.order' doesn't exist
// err = db.Model(&Order{}).Where("user_id", int64(3)).Find(&orders).Error
err = db.Table("orders").Where("user_id", int64(2)).Find(&orders).Error
if err != nil {
fmt.Println("err4", err)
}
fmt.Printf("%#v\n", orders)
// Raw SQL also supported
db.Raw("SELECT * FROM orders WHERE user_id = ?", int64(3)).Scan(&orders)
fmt.Printf("%#v\n", orders)
// this will throw ErrMissingShardingKey error
// !!!!!!!!!!!!!!!!!! it returm err: Error 1146: Table 'MyTable.order' doesn't exist
// err = db.Model(&Order{}).Where("product_id", "1").Find(&orders).Error
err = db.Table("orders").Where("product_id", "1").Find(&orders).Error
fmt.Println("err5", err)
// Update and Delete are similar to create and query
err = db.Exec("UPDATE orders SET product_id = ? WHERE user_id = ?", 2, int64(3)).Error
fmt.Println("err6", err) // nil
err = db.Exec("DELETE FROM orders WHERE product_id = 3").Error
fmt.Println("err7", err) // ErrMissingShardingKey
}
see // !!!!!!!!!!!!!!!!!! it returm err: Error 1146: Table 'MyTable.order' doesn't exist
i want use Model
to access, not Table
my code works well befor using sharding middleware:
func (r *MySQLRepo) PlanExists(id uint) (bool, error) {
var exists bool
err := r.db.Model(&entity.StockPlan{}).
Select("count(*) > 0").
Where("id = ?", id).
Find(&exists).
Error
return exists, err
}
but the error occurs after registering sharding like this:
db.Use(sharding.Register(sharding.Config{
ShardingKey: "title",
NumberOfShards: 4,
PrimaryKeyGenerator: sharding.PKSnowflake,
}, "stock_plans"))
and the error is:
Error 1054: Unknown column 'stock_plans.deleted_at' in 'where clause'
When i use preload on sharding table, the return "msg sharding key or id required, and use operator ="
type A struct {
ID string
BS []B
}
type B struct {
ID string
AID string
}
var aModel A
db.Model(&A{}).Preload("B").Find(&aModel)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.