From d55c96e3838756872bd087d236df49c0f7521319 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=98=94=E5=BF=B5?= <12574910+72wo@users.noreply.github.com> Date: Sat, 28 Mar 2026 02:22:15 +0800 Subject: [PATCH] =?UTF-8?q?```=20feat(database):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=A4=9A=E4=B8=AA=E7=8E=A9=E5=AE=B6=E7=9B=B8=E5=85=B3=E8=A1=A8?= =?UTF-8?q?=E7=9A=84=E8=81=94=E5=90=88=E5=94=AF=E4=B8=80=E7=BA=A6=E6=9D=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 为player_talk表添加玩家+挖矿联合唯一索引 - 为player_task表添加玩家+任务联合唯一索引 - 为player_title表添加玩家+称号联合唯一索引 - 为player_pet表添加玩家+精灵联合唯一索引 - 为player_cdk_log表添加玩家+CDK联合唯一索引 - 为player_egg表添加玩家孵蛋联合唯一索引 - 为player_pvp表添加PVP索引 - 为player_sign_in_log表添加签到联合唯一索引 - 为player_room_house表添加房间索引 fix(user-talk): 修复获取聊天配置 --- help/约束类.sql | 40 ++++++++++++++++++++++++++++++- logic/controller/user_talk.go | 3 +++ modules/config/model/user_talk.go | 2 +- modules/player/service/talk.go | 30 +++++++++++------------ 4 files changed, 57 insertions(+), 18 deletions(-) diff --git a/help/约束类.sql b/help/约束类.sql index f681fae3f..2acbafda4 100644 --- a/help/约束类.sql +++ b/help/约束类.sql @@ -1,4 +1,42 @@ -- 玩家+物品+VIP状态 联合唯一 ALTER TABLE player_item ADD CONSTRAINT uk_player_item_player_item_vip -UNIQUE (player_id, item_id, is_vip); \ No newline at end of file +UNIQUE (player_id, item_id, is_vip); + + +-- 玩家+挖矿 联合唯一 +CREATE UNIQUE INDEX uk_talk_player ON player_talk (talk_id, player_id); + + +-- 玩家+任务 联合唯一 +CREATE UNIQUE INDEX uk_player_task ON player_task (player_id, task_id); +-- 玩家+称号 联合唯一 +CREATE UNIQUE INDEX uk_player_title ON player_title (player_id, is_vip) WHERE deleted_at IS NULL; + +-- 玩家+精灵 联合唯一 +CREATE UNIQUE INDEX uk_player_pet ON player_pet (player_id, is_vip, catch_time) WHERE deleted_at IS NULL; + +-- 玩家+CDK 联合唯一 +CREATE UNIQUE INDEX uk_player_cdk_log +ON player_cdk_log (player_id, code_id, is_vip) +WHERE deleted_at IS NULL; + + +-- 玩家孵蛋 联合唯一 + CREATE UNIQUE INDEX uk_player_egg +ON player_egg (player_id, is_vip) +WHERE deleted_at IS NULL; + +---PVP索引 +CREATE UNIQUE INDEX uk_player_pvp +ON player_pvp (player_id, season) +WHERE deleted_at IS NULL; + +--签到 +CREATE UNIQUE INDEX uk_player_sign_in_log +ON player_sign_in_log (player_id, sign_in_id, is_vip) +WHERE deleted_at IS NULL; +--房间索引 +CREATE UNIQUE INDEX uk_player_room_house +ON player_room_house (player_id, is_vip) +WHERE deleted_at IS NULL; \ No newline at end of file diff --git a/logic/controller/user_talk.go b/logic/controller/user_talk.go index b86ad95cf..b01e8dd1a 100644 --- a/logic/controller/user_talk.go +++ b/logic/controller/user_talk.go @@ -30,6 +30,9 @@ func (h Controller) GetTalkCategory(data *item.TalkCateInboundInfo, c *player.Pl } //更新次数 config := service.NewTalkConfigService().GetCache(int(data.ID)) + if config == nil { + return result, errorcode.ErrorCodes.ErrSystemError + } //service.NewItemService().GetItemCount(config.ItemID) diff --git a/modules/config/model/user_talk.go b/modules/config/model/user_talk.go index 9c19b35a2..c36e50cc2 100644 --- a/modules/config/model/user_talk.go +++ b/modules/config/model/user_talk.go @@ -20,7 +20,7 @@ type MineralCollectionConfig struct { Type uint32 `gorm:"column:type;not null;index:idx_mineral_collection_config_type;comment:类型" json:"type"` // DailyCollectCount 每日可采集次数 - DailyCollectCount uint32 `gorm:"column:daily_collect_count;not null;comment:每日可采集次数" json:"daily_collect_count"` + DailyCollectCount uint32 `gorm:"column:daily_collect_count;not null;comment:可采集次数" json:"daily_collect_count"` // ItemID 物品编号(对应道具系统ID) ItemIDS []uint32 `gorm:"column:item_ids;type:jsonb;index:idx_mineral_collection_config_item_id;comment:物品编号(对应道具系统ID)" json:"item_ids"` diff --git a/modules/player/service/talk.go b/modules/player/service/talk.go index 155c9ce27..32f540087 100644 --- a/modules/player/service/talk.go +++ b/modules/player/service/talk.go @@ -78,7 +78,6 @@ func (s *TalkService) Cheak(mapid uint32, flag int) (int, bool) { } -// Update 原子更新,返回是否更新成功(true=成功 false=上限/失败/VIP) func (s *TalkService) Update(flag int, count int) bool { // VIP 直接返回失败 if cool.Config.ServerInfo.IsVip != 0 { @@ -96,28 +95,27 @@ func (s *TalkService) Update(flag int, count int) bool { } maxCount := int(cfg.DailyCollectCount) - // 2. 原子插入(不存在则插入,存在忽略,高并发安全) - talk := model.NewTalk() - talk.PlayerID = userID - talk.TalkID = talkID - _, _ = db.Data(talk).FieldsEx("id").InsertIgnore() + // 2. 原子操作:不存在则插入(count=0),存在则不操作 + talk := model.Talk{ + PlayerID: userID, + TalkID: talkID, + Count: 0, // 关键:必须初始化 count 为 0 + } + // 唯一索引 + InsertIgnore 保证只会插入1次 + _, _ = db.Data(talk).InsertIgnore() - // 3. 原子条件自增:只有没超过上限才会更新 - // 核心:数据库原子判断,绝对不溢出 + // 3. 原子条件自增(只有没超上限才会增加) affected, err := db. Where("talk_id = ?", talkID). + Where("player_id = ?", userID). // 关键:必须加 player_id 条件 Where("count + ? <= ?", count, maxCount). Increment("count", count) + if err != nil { - return false } + row, _ := affected.RowsAffected() - // 有错误 或 没有影响行数 = 更新失败(已达上限) - if row == 0 { - - return false - } - - return true + // 0 行受影响 = 已达上限 + return row > 0 }