game/common/model/tableOperation.go
2025-06-04 01:56:38 +08:00

158 lines
3.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package model
import (
"context"
"encoding/json"
"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"
"time"
)
const (
TableExpire = 7 * 24 * time.Hour // 七天后过期
)
type resultT[T any] struct {
ret T
//err error
}
type iTable interface {
GetId() uint
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 resultT[T]
return result.ret.TableName()
}
func (s *TableOp[T]) redisKey(id uint) string {
return fmt.Sprintf("%s:%d", s.tableName(), id)
}
func (s *TableOp[T]) findByRedis(id uint) *T {
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
}
jsonByte, _ := json.Marshal(maps)
var result resultT[T]
_ = json.Unmarshal(jsonByte, &result.ret)
log.DebugF("findByRedis redis-key:%v result:%v", s.redisKey(id), result.ret)
return &result.ret
}
func (s *TableOp[T]) writeRedis(id uint, 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)
}
func (s *TableOp[T]) updateRedis(id uint, 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 uint) {
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 uint) (*T, pb.ErrCode) {
// 先从redis中查询redis中没有则从mysql中查询
if table := s.findByRedis(id); table != nil {
return table, pb.ErrCode_OK
}
var result resultT[T]
err := s.db.Where("id = ?", id).First(&result.ret).Error
if err != nil {
log.DebugF("find table:%v id:%v err:%v", s.tableName(), id, err)
return nil, pb.ErrCode_SystemErr
}
return &result.ret, pb.ErrCode_OK
}
// 根据条件查询只在mysql中查询无法在redis中查询
func (s *TableOp[T]) FindCondition(condition map[string]any) (*T, error) {
var result resultT[T]
err := s.db.Where(condition).First(&result.ret).Error
if err != nil {
log.ErrorF("find table:%v condition:%v err:%v", s.tableName(), utils.JsonMarshal(condition), err)
return nil, err
}
// 查看redis中是否存在该键不存在则写入数据
exist, _ := s.rds.Exists(context.Background(), s.redisKey(result.ret.GetId())).Result()
if exist != 1 {
s.writeRedis(result.ret.GetId(), &result.ret)
}
return &result.ret, nil
}
func (s *TableOp[T]) Update(id uint, updates map[string]any) (*T, pb.ErrCode) {
var result resultT[T]
err := s.db.Model(&result.ret).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.ret, pb.ErrCode_OK
}
func (s *TableOp[T]) Delete(id uint) (*T, pb.ErrCode) {
var result resultT[T]
err := s.db.Delete(&result.ret, 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.ret, pb.ErrCode_OK
}