2025-05-31 23:34:58 +08:00
|
|
|
|
package model
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"fmt"
|
|
|
|
|
"game/common/proto/pb"
|
|
|
|
|
"game/common/serialization"
|
2025-06-02 01:07:35 +08:00
|
|
|
|
"game/common/utils"
|
2025-05-31 23:34:58 +08:00
|
|
|
|
"github.com/fox/fox/log"
|
|
|
|
|
"github.com/go-redis/redis/v8"
|
|
|
|
|
"gorm.io/gorm"
|
|
|
|
|
"time"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
const (
|
2025-06-02 01:07:35 +08:00
|
|
|
|
TableExpire = 7 * 24 * time.Hour // 七天后过期
|
2025-05-31 23:34:58 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type iTable interface {
|
2025-06-06 00:09:10 +08:00
|
|
|
|
GetId() int64
|
2025-06-04 01:56:38 +08:00
|
|
|
|
TableName() string
|
2025-05-31 23:34:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
T:Table,如果不想操作redis则将rds设置为nil
|
|
|
|
|
*/
|
|
|
|
|
type TableOp[T iTable] struct {
|
|
|
|
|
db *gorm.DB
|
|
|
|
|
rds *redis.Client
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-02 01:07:35 +08:00
|
|
|
|
func NewTableOp[T iTable](db *gorm.DB, rds *redis.Client) *TableOp[T] {
|
2025-05-31 23:34:58 +08:00
|
|
|
|
return &TableOp[T]{db: db, rds: rds}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *TableOp[T]) tableName() string {
|
2025-06-14 16:40:15 +08:00
|
|
|
|
var result utils.TValue[T]
|
|
|
|
|
return result.V.TableName()
|
2025-05-31 23:34:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-06-06 00:09:10 +08:00
|
|
|
|
func (s *TableOp[T]) redisKey(id int64) string {
|
2025-05-31 23:34:58 +08:00
|
|
|
|
return fmt.Sprintf("%s:%d", s.tableName(), id)
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-06 00:09:10 +08:00
|
|
|
|
func (s *TableOp[T]) findByRedis(id int64) *T {
|
2025-05-31 23:34:58 +08:00
|
|
|
|
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
|
|
|
|
|
}
|
2025-06-04 23:21:21 +08:00
|
|
|
|
us, err := serialization.MapToStruct[T](maps)
|
2025-06-04 02:40:13 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
log.ErrorF("serialization map to struct err: %v", err)
|
|
|
|
|
return nil
|
|
|
|
|
}
|
2025-06-05 00:05:09 +08:00
|
|
|
|
//log.DebugF("findByRedis redis-key:%v result:%v", s.redisKey(id), us)
|
|
|
|
|
return us
|
2025-05-31 23:34:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-06-06 00:09:10 +08:00
|
|
|
|
func (s *TableOp[T]) writeRedis(id int64, t *T) {
|
2025-05-31 23:34:58 +08:00
|
|
|
|
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)
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-14 16:40:15 +08:00
|
|
|
|
// 查看在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
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-06 00:09:10 +08:00
|
|
|
|
func (s *TableOp[T]) updateRedis(id int64, maps map[string]any) {
|
2025-05-31 23:34:58 +08:00
|
|
|
|
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)
|
|
|
|
|
}
|
2025-06-02 01:07:35 +08:00
|
|
|
|
_ = s.rds.Expire(context.Background(), s.redisKey(id), TableExpire).Err()
|
2025-05-31 23:34:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-06-14 16:40:15 +08:00
|
|
|
|
func (s *TableOp[T]) addRedis(id int64, maps map[string]int64) map[string]int64 {
|
|
|
|
|
if s.rds == nil {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
rets := map[string]int64{}
|
|
|
|
|
for k, v := range maps {
|
|
|
|
|
if ret, err := s.rds.HIncrBy(context.Background(), s.redisKey(id), k, v).Result(); err != nil {
|
|
|
|
|
log.ErrorF("redis-key:%v HIncrBy field err: %v", s.redisKey(id), k, err)
|
|
|
|
|
} else {
|
|
|
|
|
rets[k] = ret
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_ = s.rds.Expire(context.Background(), s.redisKey(id), TableExpire).Err()
|
|
|
|
|
return rets
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-06 00:09:10 +08:00
|
|
|
|
func (s *TableOp[T]) deleteRedis(id int64) {
|
2025-05-31 23:34:58 +08:00
|
|
|
|
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
|
|
|
|
|
}
|
2025-06-02 01:07:35 +08:00
|
|
|
|
s.writeRedis((*t).GetId(), t)
|
2025-05-31 23:34:58 +08:00
|
|
|
|
return t, pb.ErrCode_OK
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-06 00:09:10 +08:00
|
|
|
|
func (s *TableOp[T]) Find(id int64) (*T, pb.ErrCode) {
|
2025-05-31 23:34:58 +08:00
|
|
|
|
// 先从redis中查询,redis中没有则从mysql中查询
|
|
|
|
|
if table := s.findByRedis(id); table != nil {
|
|
|
|
|
return table, pb.ErrCode_OK
|
|
|
|
|
}
|
2025-06-14 16:40:15 +08:00
|
|
|
|
var result utils.TValue[T]
|
|
|
|
|
err := s.db.Where("id = ?", id).First(&result.V).Error
|
2025-05-31 23:34:58 +08:00
|
|
|
|
if err != nil {
|
2025-06-04 01:56:38 +08:00
|
|
|
|
log.DebugF("find table:%v id:%v err:%v", s.tableName(), id, err)
|
2025-05-31 23:34:58 +08:00
|
|
|
|
return nil, pb.ErrCode_SystemErr
|
|
|
|
|
}
|
2025-06-14 16:40:15 +08:00
|
|
|
|
return &result.V, pb.ErrCode_OK
|
2025-05-31 23:34:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-06-02 01:07:35 +08:00
|
|
|
|
// 根据条件查询,只在mysql中查询,无法在redis中查询
|
|
|
|
|
func (s *TableOp[T]) FindCondition(condition map[string]any) (*T, error) {
|
2025-06-14 16:40:15 +08:00
|
|
|
|
var result utils.TValue[T]
|
|
|
|
|
err := s.db.Where(condition).First(&result.V).Error
|
2025-06-02 01:07:35 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
log.ErrorF("find table:%v condition:%v err:%v", s.tableName(), utils.JsonMarshal(condition), err)
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
// 查看redis中是否存在该键,不存在则写入数据
|
2025-06-14 16:40:15 +08:00
|
|
|
|
if !s.existRedis(&result.V) {
|
|
|
|
|
s.writeRedis(result.V.GetId(), &result.V)
|
2025-06-02 01:07:35 +08:00
|
|
|
|
}
|
2025-06-14 16:40:15 +08:00
|
|
|
|
return &result.V, nil
|
2025-06-02 01:07:35 +08:00
|
|
|
|
}
|
2025-05-31 23:34:58 +08:00
|
|
|
|
|
2025-06-06 00:09:10 +08:00
|
|
|
|
func (s *TableOp[T]) Update(id int64, updates map[string]any) (*T, pb.ErrCode) {
|
2025-06-14 16:40:15 +08:00
|
|
|
|
var result utils.TValue[T]
|
|
|
|
|
err := s.db.Model(&result.V).Where("id = ?", id).Updates(updates).Error
|
2025-05-31 23:34:58 +08:00
|
|
|
|
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)
|
2025-06-14 16:40:15 +08:00
|
|
|
|
return &result.V, pb.ErrCode_OK
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *TableOp[T]) Add(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
|
|
|
|
|
}
|
|
|
|
|
rets := s.addRedis(id, res)
|
|
|
|
|
return rets, pb.ErrCode_OK
|
2025-05-31 23:34:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-06-06 00:09:10 +08:00
|
|
|
|
func (s *TableOp[T]) Delete(id int64) (*T, pb.ErrCode) {
|
2025-06-14 16:40:15 +08:00
|
|
|
|
var result utils.TValue[T]
|
|
|
|
|
err := s.db.Delete(&result.V, id).Error
|
2025-05-31 23:34:58 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
log.ErrorF("delete table:%v err:%v", s.tableName(), err)
|
|
|
|
|
return nil, pb.ErrCode_SystemErr
|
|
|
|
|
}
|
|
|
|
|
s.deleteRedis(id)
|
2025-06-14 16:40:15 +08:00
|
|
|
|
return &result.V, pb.ErrCode_OK
|
2025-05-31 23:34:58 +08:00
|
|
|
|
}
|