```
All checks were successful
ci/woodpecker/push/my-first-workflow Pipeline was successful

feat(database): 添加多个玩家相关表的联合唯一约束

- 为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): 修复获取聊天配置
This commit is contained in:
昔念
2026-03-28 02:22:15 +08:00
parent 06091ff42c
commit d55c96e383
4 changed files with 57 additions and 18 deletions

View File

@@ -1,4 +1,42 @@
-- 玩家+物品+VIP状态 联合唯一 -- 玩家+物品+VIP状态 联合唯一
ALTER TABLE player_item ALTER TABLE player_item
ADD CONSTRAINT uk_player_item_player_item_vip ADD CONSTRAINT uk_player_item_player_item_vip
UNIQUE (player_id, item_id, is_vip); 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;

View File

@@ -30,6 +30,9 @@ func (h Controller) GetTalkCategory(data *item.TalkCateInboundInfo, c *player.Pl
} }
//更新次数 //更新次数
config := service.NewTalkConfigService().GetCache(int(data.ID)) config := service.NewTalkConfigService().GetCache(int(data.ID))
if config == nil {
return result, errorcode.ErrorCodes.ErrSystemError
}
//service.NewItemService().GetItemCount(config.ItemID) //service.NewItemService().GetItemCount(config.ItemID)

View File

@@ -20,7 +20,7 @@ type MineralCollectionConfig struct {
Type uint32 `gorm:"column:type;not null;index:idx_mineral_collection_config_type;comment:类型" json:"type"` Type uint32 `gorm:"column:type;not null;index:idx_mineral_collection_config_type;comment:类型" json:"type"`
// DailyCollectCount 每日可采集次数 // 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 // ItemID 物品编号对应道具系统ID
ItemIDS []uint32 `gorm:"column:item_ids;type:jsonb;index:idx_mineral_collection_config_item_id;comment:物品编号对应道具系统ID" json:"item_ids"` ItemIDS []uint32 `gorm:"column:item_ids;type:jsonb;index:idx_mineral_collection_config_item_id;comment:物品编号对应道具系统ID" json:"item_ids"`

View File

@@ -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 { func (s *TalkService) Update(flag int, count int) bool {
// VIP 直接返回失败 // VIP 直接返回失败
if cool.Config.ServerInfo.IsVip != 0 { if cool.Config.ServerInfo.IsVip != 0 {
@@ -96,28 +95,27 @@ func (s *TalkService) Update(flag int, count int) bool {
} }
maxCount := int(cfg.DailyCollectCount) maxCount := int(cfg.DailyCollectCount)
// 2. 原子插入(不存在则插入,存在忽略,高并发安全) // 2. 原子操作:不存在则插入count=0存在则不操作
talk := model.NewTalk() talk := model.Talk{
talk.PlayerID = userID PlayerID: userID,
talk.TalkID = talkID TalkID: talkID,
_, _ = db.Data(talk).FieldsEx("id").InsertIgnore() Count: 0, // 关键:必须初始化 count 为 0
}
// 唯一索引 + InsertIgnore 保证只会插入1次
_, _ = db.Data(talk).InsertIgnore()
// 3. 原子条件自增只有没超上限才会更新 // 3. 原子条件自增只有没超上限才会增加)
// 核心:数据库原子判断,绝对不溢出
affected, err := db. affected, err := db.
Where("talk_id = ?", talkID). Where("talk_id = ?", talkID).
Where("player_id = ?", userID). // 关键:必须加 player_id 条件
Where("count + ? <= ?", count, maxCount). Where("count + ? <= ?", count, maxCount).
Increment("count", count) Increment("count", count)
if err != nil { if err != nil {
return false return false
} }
row, _ := affected.RowsAffected() row, _ := affected.RowsAffected()
// 有错误 或 没有影响行数 = 更新失败(已达上限 // 0 行受影响 = 已达上限
if row == 0 { return row > 0
return false
}
return true
} }