gorm多租户插件的使用
一、关于gorm
多租户插件的使用
-
1、安装依赖
go get -u github.com/kuangshp/gorm-tenant
-
2、创建一个
mysql
数据表DROP TABLE IF EXISTS `user`; CREATE TABLE `user` (`id` int(11) NOT NULL AUTO_INCREMENT primary key COMMENT '主键id',`name` varchar(50) not null comment '名称',`tenant_id` int(11) default 0 comment '租户id',`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',`deleted_at` datetime NULL DEFAULT NULL COMMENT '软删除时间' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
-
3、将数据库文件同步生成
go
的数据模型type UserEntity struct {ID int64 `gorm:"column:id;type:int;primaryKey;autoIncrement:true;comment:主键id" json:"id"` // 主键idName string `gorm:"column:name;type:varchar(50);not null;comment:名称" json:"name"` // 名称TenantID int64 `gorm:"column:tenant_id;type:int;comment:租户id" json:"tenantId"` // 租户idCreatedAt time.Time `gorm:"column:created_at;comment:创建时间" json:"createdAt"` // 创建时间UpdatedAt time.Time `gorm:"column:updated_at;comment:更新时间" json:"updatedAt"` // 更新时间DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;type:datetime;comment:软删除时间" json:"-"` // 软删除时间 }
-
4、在创建数据库连接的时候使用插件
func NewMysqlDB(username, password, host, port, database, charset, loc string) *gorm.DB {// 字符串拼接dataSource := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=%s&parseTime=true&loc=%s",username,password,host,port,database,charset,url.QueryEscape(loc),)fmt.Println(dataSource, "数据库连接")db, err := gorm.Open(mysql.Open(dataSource), &gorm.Config{Logger: logger.Default.LogMode(logger.Info),DisableForeignKeyConstraintWhenMigrating: true, // 自动创建表的时候不创建外键SkipDefaultTransaction: false,NamingStrategy: schema.NamingStrategy{ // 自动创建表时候表名的配置SingularTable: true,},})if err != nil {panic("连接数据库失败")}dao.SetDefault(db)// 多租户插件db.Use(&gormTenant.TenantPlugin{)fmt.Println("mysql启动成功...")return db }
-
5、在操作的时候使用自己的上下文就可以,本案例使用的是
go-zero
来实现func NewGetUserListApiLogic(ctx context.Context, svcCtx *svc.ServiceContext, request *http.Request) *GetUserListApiLogic {hostname, _ := os.Hostname()return &GetUserListApiLogic{Logger: logx.WithContext(ctx).WithCallerSkip(0).WithFields(logx.Field("Log_UUID", uuid.New().String()),logx.Field("hostname", hostname)),ctx: gormTenant.NewContext(ctx), // 这个替换官方生成的svcCtx: svcCtx,Request: request,} }
-
6、查询和不使用租户的查询方式(关于租户传值的后面会介绍)
// 使用了租户字段 dao.UserEntity.WithContext(l.ctx).Where(dao.UserEntity.Name.Eq("你好")).Find() // SELECT * FROM `user` WHERE `user`.`name` = '你好' AND `user`.`tenant_id` = 455 AND `user`.`deleted_at` IS NULL // 不使用租户 dao.UserEntity.WithContext(tenant.SkipTenantContext(l.ctx)).Find() // SELECT * FROM `user` WHERE `user`.`deleted_at` IS NULL
二、关于tenant_id
传递值
-
1、在
go-zero
中将租户信息在中间件中写入到上下文中func (m *AuthMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {return func(w http.ResponseWriter, r *http.Request) {...ctx = context.WithValue(ctx, "tenant_id", "455")next(w, r.WithContext(ctx))} }
三、关于数据库字段不是叫tenant_id
-
1、比如现在数据库模型租户字段叫
TenantNo
,直接在使用的时候传递数据库字段db.Use(&tenant.TenantPlugin{TenantField: "TenantNo"})
四、如果上下文件中定义租户字段不是叫tenant_id
-
1、在重写
ctx
的时候可以传递你上下文中定义的字段gormTenant.NewContext(ctx,"test1") // 注意test1要保持和上下文一致就可以