将表操作挪到外面
This commit is contained in:
parent
f0600752e5
commit
37ef9a8a30
@ -1 +1 @@
|
|||||||
Subproject commit cad5b2a6f2f5b6bb82d4bbe6cdda49b4c1b26e9e
|
Subproject commit 314f58680be0d9ed55f1b0fe52234f16da93c7cd
|
264
common/modelOperator/tableOperator.go
Normal file
264
common/modelOperator/tableOperator.go
Normal file
@ -0,0 +1,264 @@
|
|||||||
|
package modelOperator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"game/common/proto/pb"
|
||||||
|
"game/common/serialization"
|
||||||
|
"game/common/utils"
|
||||||
|
"github.com/fox/fox/log"
|
||||||
|
"github.com/go-redis/redis/v8"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
TableExpire = 7 * 24 * time.Hour // 七天后过期
|
||||||
|
)
|
||||||
|
|
||||||
|
type iTable interface {
|
||||||
|
GetId() int64
|
||||||
|
TableName() string
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
T:Table,如果不想操作redis则将rds设置为nil
|
||||||
|
*/
|
||||||
|
type TableOp[T iTable] struct {
|
||||||
|
db *gorm.DB
|
||||||
|
rds *redis.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTableOp[T iTable](db *gorm.DB, rds *redis.Client) *TableOp[T] {
|
||||||
|
return &TableOp[T]{db: db, rds: rds}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *TableOp[T]) tableName() string {
|
||||||
|
var result utils.TValue[T]
|
||||||
|
return result.V.TableName()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *TableOp[T]) redisKey(id int64) string {
|
||||||
|
return fmt.Sprintf("%s:%d", s.tableName(), id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查找并返回结构体
|
||||||
|
func (s *TableOp[T]) findByRedis(id int64) *T {
|
||||||
|
maps := s.findByRedisMaps(id)
|
||||||
|
if len(maps) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
us, err := serialization.MapToStruct[T](maps)
|
||||||
|
if err != nil {
|
||||||
|
log.ErrorF("serialization map to struct err: %v", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
//log.DebugF("findByRedis redis-key:%v result:%v", s.redisKey(id), us)
|
||||||
|
return us
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查找并返回map
|
||||||
|
func (s *TableOp[T]) findByRedisMaps(id int64) map[string]string {
|
||||||
|
if s.rds == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
maps, err := s.rds.HGetAll(context.Background(), s.redisKey(id)).Result()
|
||||||
|
if err != nil {
|
||||||
|
log.ErrorF("redis-key:%v HGetAll err: %v", s.redisKey(id), err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if len(maps) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return maps
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *TableOp[T]) writeRedis(id int64, t *T) {
|
||||||
|
if s.rds == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
maps := serialization.StructToMap(t)
|
||||||
|
if len(maps) == 0 {
|
||||||
|
log.ErrorF("table struct is empty:%v", s.tableName())
|
||||||
|
}
|
||||||
|
s.updateRedis(id, maps)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查看在redis中是否存在
|
||||||
|
func (s *TableOp[T]) existRedis(t *T) bool {
|
||||||
|
if s.rds == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// 查看redis中是否存在该键
|
||||||
|
exist, _ := s.rds.Exists(context.Background(), s.redisKey((*t).GetId())).Result()
|
||||||
|
return exist == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *TableOp[T]) updateRedis(id int64, maps map[string]any) {
|
||||||
|
if s.rds == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := s.rds.HMSet(context.Background(), s.redisKey(id), maps).Err(); err != nil {
|
||||||
|
log.ErrorF("redis-key:%v HMSet err: %v", s.redisKey(id), err)
|
||||||
|
}
|
||||||
|
_ = s.rds.Expire(context.Background(), s.redisKey(id), TableExpire).Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *TableOp[T]) deleteRedis(id int64) {
|
||||||
|
if s.rds == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_ = s.rds.Del(context.Background(), s.redisKey(id)).Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *TableOp[T]) Create(t *T) (*T, pb.ErrCode) {
|
||||||
|
if err := s.db.Create(t).Error; err != nil {
|
||||||
|
log.ErrorF("create table:%v err:%v", s.tableName(), err)
|
||||||
|
return nil, pb.ErrCode_SystemErr
|
||||||
|
}
|
||||||
|
s.writeRedis((*t).GetId(), t)
|
||||||
|
return t, pb.ErrCode_OK
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *TableOp[T]) Find(id int64) (*T, pb.ErrCode) {
|
||||||
|
// 先从redis中查询,redis中没有则从mysql中查询
|
||||||
|
if table := s.findByRedis(id); table != nil {
|
||||||
|
return table, pb.ErrCode_OK
|
||||||
|
}
|
||||||
|
var result utils.TValue[T]
|
||||||
|
err := s.db.Where("id = ?", id).First(&result.V).Error
|
||||||
|
if err != nil {
|
||||||
|
log.DebugF("find table:%v id:%v err:%v", s.tableName(), id, err)
|
||||||
|
return nil, pb.ErrCode_SystemErr
|
||||||
|
}
|
||||||
|
return &result.V, pb.ErrCode_OK
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据条件查询,只在mysql中查询,无法在redis中查询
|
||||||
|
func (s *TableOp[T]) FindCondition(condition map[string]any) (*T, pb.ErrCode) {
|
||||||
|
us := new(T)
|
||||||
|
err := s.db.Where(condition).First(us).Error
|
||||||
|
if err != nil {
|
||||||
|
log.ErrorF("find table:%v condition:%v err:%v", s.tableName(), utils.JsonMarshal(condition), err)
|
||||||
|
return nil, pb.ErrCode_SystemErr
|
||||||
|
}
|
||||||
|
// 查看redis中是否存在该键,不存在则写入数据
|
||||||
|
if !s.existRedis(us) {
|
||||||
|
s.writeRedis((*us).GetId(), us)
|
||||||
|
}
|
||||||
|
return us, pb.ErrCode_OK
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *TableOp[T]) Update(id int64, updates map[string]any) (*T, pb.ErrCode) {
|
||||||
|
var result utils.TValue[T]
|
||||||
|
err := s.db.Model(&result.V).Where("id = ?", id).Updates(updates).Error
|
||||||
|
if err != nil {
|
||||||
|
log.ErrorF("update table:%v id:%v err:%v", s.tableName(), id, err)
|
||||||
|
return nil, pb.ErrCode_SystemErr
|
||||||
|
}
|
||||||
|
s.updateRedis(id, updates)
|
||||||
|
return &result.V, pb.ErrCode_OK
|
||||||
|
}
|
||||||
|
|
||||||
|
// 辅助函数:将map的keys转为字符串slice
|
||||||
|
func keysToStringSlice(m map[string]int64) []string {
|
||||||
|
keys := make([]string, 0, len(m))
|
||||||
|
for k := range m {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
return keys
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取资源
|
||||||
|
func (s *TableOp[T]) GetInt(id int64, resName []string) (map[string]int64, pb.ErrCode) {
|
||||||
|
mapFields := s.findByRedisMaps(id)
|
||||||
|
// 查询更新后的值到map
|
||||||
|
updatedValues := make(map[string]int64)
|
||||||
|
if len(mapFields) != 0 {
|
||||||
|
for _, name := range resName {
|
||||||
|
v, _ := strconv.ParseInt(mapFields[name], 10, 64)
|
||||||
|
updatedValues[name] = v
|
||||||
|
}
|
||||||
|
return updatedValues, pb.ErrCode_OK
|
||||||
|
}
|
||||||
|
|
||||||
|
// redis中没有值,从表中加载并写入redis
|
||||||
|
mapAny := make(map[string]any)
|
||||||
|
err := s.db.Model(new(T)).
|
||||||
|
Where("id = ?", id).
|
||||||
|
Take(&mapAny). // 扫描到map
|
||||||
|
Error
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.ErrorF("query updated values table:%v id:%v err:%v", s.tableName(), id, err)
|
||||||
|
return nil, pb.ErrCode_SystemErr
|
||||||
|
}
|
||||||
|
s.updateRedis(id, mapAny)
|
||||||
|
|
||||||
|
// 查询更新后的值到map
|
||||||
|
updatedValues = make(map[string]int64)
|
||||||
|
for _, name := range resName {
|
||||||
|
if val, ok := mapAny[name]; ok {
|
||||||
|
var v64 int64
|
||||||
|
switch v := val.(type) {
|
||||||
|
case int64:
|
||||||
|
v64 = v
|
||||||
|
case int, int32, uint, uint32, uint64:
|
||||||
|
v64 = reflect.ValueOf(v).Int()
|
||||||
|
case float32, float64:
|
||||||
|
v64 = int64(reflect.ValueOf(v).Float())
|
||||||
|
default:
|
||||||
|
// 处理无法转换的情况
|
||||||
|
}
|
||||||
|
updatedValues[name] = v64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return updatedValues, pb.ErrCode_OK
|
||||||
|
}
|
||||||
|
|
||||||
|
// 增加或减少资源
|
||||||
|
func (s *TableOp[T]) AddInt(id int64, res map[string]int64) (map[string]int64, pb.ErrCode) {
|
||||||
|
addRes := map[string]any{}
|
||||||
|
for k, v := range res {
|
||||||
|
addRes[k] = gorm.Expr(fmt.Sprintf("%v + ?", k), v)
|
||||||
|
}
|
||||||
|
var result utils.TValue[T]
|
||||||
|
err := s.db.Model(&result.V).Where("id = ?", id).Updates(addRes).Error
|
||||||
|
if err != nil {
|
||||||
|
log.ErrorF("add table:%v id:%v err:%v", s.tableName(), id, err)
|
||||||
|
return nil, pb.ErrCode_SystemErr
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询更新后的值到map
|
||||||
|
updatedValues := make(map[string]int64)
|
||||||
|
err = s.db.Model(new(T)).
|
||||||
|
Select(keysToStringSlice(res)). // 只选择需要返回的字段
|
||||||
|
Where("id = ?", id).
|
||||||
|
Take(&updatedValues). // 扫描到map
|
||||||
|
Error
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.ErrorF("query updated values table:%v id:%v err:%v", s.tableName(), id, err)
|
||||||
|
return nil, pb.ErrCode_SystemErr
|
||||||
|
}
|
||||||
|
|
||||||
|
mapAny := make(map[string]any)
|
||||||
|
for k, v := range updatedValues {
|
||||||
|
mapAny[k] = v
|
||||||
|
}
|
||||||
|
s.updateRedis(id, mapAny)
|
||||||
|
return updatedValues, pb.ErrCode_OK
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *TableOp[T]) Delete(id int64) (*T, pb.ErrCode) {
|
||||||
|
var result utils.TValue[T]
|
||||||
|
err := s.db.Delete(&result.V, id).Error
|
||||||
|
if err != nil {
|
||||||
|
log.ErrorF("delete table:%v err:%v", s.tableName(), err)
|
||||||
|
return nil, pb.ErrCode_SystemErr
|
||||||
|
}
|
||||||
|
s.deleteRedis(id)
|
||||||
|
return &result.V, pb.ErrCode_OK
|
||||||
|
}
|
@ -4,8 +4,8 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"game/common/model"
|
|
||||||
"game/common/model/user"
|
"game/common/model/user"
|
||||||
|
"game/common/modelOperator"
|
||||||
"game/common/proto/pb"
|
"game/common/proto/pb"
|
||||||
"game/common/utils"
|
"game/common/utils"
|
||||||
"github.com/fox/fox/log"
|
"github.com/fox/fox/log"
|
||||||
@ -19,7 +19,7 @@ import (
|
|||||||
type UserOp struct {
|
type UserOp struct {
|
||||||
db *gorm.DB
|
db *gorm.DB
|
||||||
userRedis *redis.Client
|
userRedis *redis.Client
|
||||||
*model.TableOp[user.User]
|
*modelOperator.TableOp[user.User]
|
||||||
}
|
}
|
||||||
|
|
||||||
// 玩家表
|
// 玩家表
|
||||||
@ -27,7 +27,7 @@ func NewUserOp() *UserOp {
|
|||||||
return &UserOp{
|
return &UserOp{
|
||||||
db: UserDB,
|
db: UserDB,
|
||||||
userRedis: UserRedis,
|
userRedis: UserRedis,
|
||||||
TableOp: model.NewTableOp[user.User](UserDB, UserRedis),
|
TableOp: modelOperator.NewTableOp[user.User](UserDB, UserRedis),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,6 +103,6 @@ func (s *UserOp) createUserAccountId(accountId int64) (*user.User, pb.ErrCode) {
|
|||||||
return nil, code
|
return nil, code
|
||||||
}
|
}
|
||||||
// 建立索引
|
// 建立索引
|
||||||
_ = s.userRedis.Set(context.Background(), s.redisKey(us.AccountId), us.ID, model.TableExpire).Err()
|
_ = s.userRedis.Set(context.Background(), s.redisKey(us.AccountId), us.ID, modelOperator.TableExpire).Err()
|
||||||
return us, pb.ErrCode_OK
|
return us, pb.ErrCode_OK
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
package operation
|
package operation
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"game/common/model"
|
|
||||||
"game/common/model/user"
|
"game/common/model/user"
|
||||||
|
"game/common/modelOperator"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 游戏对局日志
|
// 游戏对局日志
|
||||||
func NewGameRecordLogOp() *model.TableOp[user.GameRecordLog] {
|
func NewGameRecordLogOp() *modelOperator.TableOp[user.GameRecordLog] {
|
||||||
return model.NewTableOp[user.GameRecordLog](LogDB, nil)
|
return modelOperator.NewTableOp[user.GameRecordLog](LogDB, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 玩家游戏日志
|
// 玩家游戏日志
|
||||||
func NewUserRecordLogOp() *model.TableOp[user.UserRecordLog] {
|
func NewUserRecordLogOp() *modelOperator.TableOp[user.UserRecordLog] {
|
||||||
return model.NewTableOp[user.UserRecordLog](LogDB, nil)
|
return modelOperator.NewTableOp[user.UserRecordLog](LogDB, nil)
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
package operation
|
package operation
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"game/common/model"
|
|
||||||
"game/common/model/user"
|
"game/common/model/user"
|
||||||
|
"game/common/modelOperator"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 玩家资源表
|
// 玩家资源表
|
||||||
func NewUserResourcesOp() *model.TableOp[user.UserResources] {
|
func NewUserResourcesOp() *modelOperator.TableOp[user.UserResources] {
|
||||||
return model.NewTableOp[user.UserResources](UserDB, UserRedis)
|
return modelOperator.NewTableOp[user.UserResources](UserDB, UserRedis)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 玩家资源表
|
// 玩家资源表
|
||||||
func NewUserResourcesLogOp() *model.TableOp[user.UserResourcesLog] {
|
func NewUserResourcesLogOp() *modelOperator.TableOp[user.UserResourcesLog] {
|
||||||
return model.NewTableOp[user.UserResourcesLog](LogDB, nil)
|
return modelOperator.NewTableOp[user.UserResourcesLog](LogDB, nil)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user