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:
40
help/约束类.sql
40
help/约束类.sql
@@ -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;
|
||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -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"`
|
||||||
|
|||||||
@@ -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
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user