优化数据库操作,批量更新角色资源、武将体力、战报和建筑,使用事务提升性能

This commit is contained in:
ytc1012
2025-11-19 11:59:51 +08:00
parent de90ad79ea
commit 8f9476e4d7
7 changed files with 412 additions and 181 deletions

View File

@@ -0,0 +1,11 @@
{
"permissions": {
"allow": [
"Bash(nul)",
"Bash(go build:*)",
"Bash(gofmt:*)"
],
"deny": [],
"ask": []
}
}

2
.gitattributes vendored Normal file
View File

@@ -0,0 +1,2 @@
* text=auto eol=lf
*.go text eol=lf

View File

@@ -14,7 +14,6 @@ import (
var DefaultWar = War{} var DefaultWar = War{}
type War struct { type War struct {
} }
func (this *War) InitRouter(r *net.Router) { func (this *War) InitRouter(r *net.Router) {
@@ -65,14 +64,37 @@ func (this*War) read(req *net.WsMsgReq, rsp *net.WsMsgRsp) {
role := r.(*model.Role) role := r.(*model.Role)
if reqObj.Id == 0 { if reqObj.Id == 0 {
// 批量标记所有战报为已读 - 使用事务优化
m := model.WarReport{AttackIsRead: true, DefenseIsRead: true} m := model.WarReport{AttackIsRead: true, DefenseIsRead: true}
_, err := db.MasterDB.Table(model.WarReport{}).Where("a_rid=?", role.RId).Cols("a_is_read").Update(m) sess := db.MasterDB.NewSession()
if err != nil { defer sess.Close()
slog.Error("db error", "error", err)
if err := sess.Begin(); err != nil {
slog.Error("begin transaction error", "error", err)
rsp.Body.Code = constant.DBError
return
} }
_, err = db.MasterDB.Table(model.WarReport{}).Where("d_rid=?", role.RId).Cols("d_is_read").Update(m)
if err != nil { // 更新攻击方战报
slog.Error("db error", "error", err) if _, err := sess.Table(model.WarReport{}).Where("a_rid=?", role.RId).Cols("a_is_read").Update(m); err != nil {
slog.Error("update attack reports error", "error", err)
sess.Rollback()
rsp.Body.Code = constant.DBError
return
}
// 更新防守方战报
if _, err := sess.Table(model.WarReport{}).Where("d_rid=?", role.RId).Cols("d_is_read").Update(m); err != nil {
slog.Error("update defense reports error", "error", err)
sess.Rollback()
rsp.Body.Code = constant.DBError
return
}
if err := sess.Commit(); err != nil {
slog.Error("commit transaction error", "error", err)
rsp.Body.Code = constant.DBError
return
} }
} else { } else {
wr := &model.WarReport{} wr := &model.WarReport{}

View File

@@ -29,13 +29,42 @@ func (this*generalMgr) updatePhysicalPower() {
for true { for true {
time.Sleep(1 * time.Hour) time.Sleep(1 * time.Hour)
this.mutex.RLock() this.mutex.RLock()
// 收集需要更新的武将ID和体力值
updateList := make([]*model.General, 0)
for _, g := range this.genByGId { for _, g := range this.genByGId {
if g.PhysicalPower < limit { if g.PhysicalPower < limit {
g.PhysicalPower = util.MinInt(limit, g.PhysicalPower+recoverCnt) g.PhysicalPower = util.MinInt(limit, g.PhysicalPower+recoverCnt)
g.SyncExecute() updateList = append(updateList, g)
} }
} }
this.mutex.RUnlock() this.mutex.RUnlock()
// 批量更新数据库 - 使用事务提升性能
if len(updateList) > 0 {
sess := db.MasterDB.NewSession()
defer sess.Close()
if err := sess.Begin(); err != nil {
slog.Warn("begin transaction error", "error", err)
continue
}
for _, g := range updateList {
if _, err := sess.ID(g.Id).Cols("physical_power").Update(g); err != nil {
slog.Warn("update general physical power error", "gid", g.Id, "error", err)
sess.Rollback()
goto CONTINUE
}
}
if err := sess.Commit(); err != nil {
slog.Warn("commit transaction error", "error", err)
} else {
slog.Debug("batch update general physical power", "count", len(updateList))
}
}
CONTINUE:
} }
} }
@@ -81,8 +110,6 @@ func (this*generalMgr) add(g *model.General) {
this.mutex.Unlock() this.mutex.Unlock()
} }
func (this *generalMgr) Load() { func (this *generalMgr) Load() {
err := db.MasterDB.Table(model.General{}).Where("state=?", err := db.MasterDB.Table(model.General{}).Where("state=?",
@@ -248,7 +275,6 @@ func (this*generalMgr) GetOrCreateByRId(rid int) ([]*model.General, bool){
} }
} }
/* /*
随机创建一个 随机创建一个
*/ */
@@ -275,7 +301,6 @@ func (this*generalMgr) RandCreateGeneral(rid int, nums int) ([]*model.General, b
} }
} }
// 获取npc武将 // 获取npc武将
func (this *generalMgr) GetNPCGenerals(cnt int, star int8, level int8) ([]model.General, bool) { func (this *generalMgr) GetNPCGenerals(cnt int, star int8, level int8) ([]model.General, bool) {
gs, ok := this.GetByRId(0) gs, ok := this.GetByRId(0)
@@ -341,12 +366,50 @@ func (this *generalMgr) TryUsePhysicalPower(army *model.Army, cost int) bool{
return false return false
} }
// 收集需要更新的武将
updateList := make([]*model.General, 0, len(army.Gens))
for _, g := range army.Gens { for _, g := range army.Gens {
if g == nil { if g == nil {
continue continue
} }
g.PhysicalPower -= cost g.PhysicalPower -= cost
g.SyncExecute() updateList = append(updateList, g)
}
// 批量更新数据库 - 使用事务
if len(updateList) > 0 {
sess := db.MasterDB.NewSession()
defer sess.Close()
if err := sess.Begin(); err != nil {
slog.Warn("begin transaction error", "error", err)
// 回滚内存中的修改
for _, g := range updateList {
g.PhysicalPower += cost
}
return false
}
for _, g := range updateList {
if _, err := sess.ID(g.Id).Cols("physical_power").Update(g); err != nil {
slog.Warn("update general physical power error", "gid", g.Id, "error", err)
sess.Rollback()
// 回滚内存中的修改
for _, g := range updateList {
g.PhysicalPower += cost
}
return false
}
}
if err := sess.Commit(); err != nil {
slog.Warn("commit transaction error", "error", err)
// 回滚内存中的修改
for _, g := range updateList {
g.PhysicalPower += cost
}
return false
}
} }
return true return true

View File

@@ -30,21 +30,35 @@ func (this*roleAttributeMgr) Load() {
} }
l := UnionMgr.List() l := UnionMgr.List()
// 收集需要创建的角色属性
needCreate := make([]*model.RoleAttribute, 0)
for _, c := range l { for _, c := range l {
for _, rid := range c.MemberArray { for _, rid := range c.MemberArray {
attr, ok := this.attribute[rid] attr, ok := this.attribute[rid]
if ok { if ok {
attr.UnionId = c.Id attr.UnionId = c.Id
} else { } else {
attr := this.create(rid) // 批量收集需要创建的属性
if attr != nil{ newAttr := &model.RoleAttribute{RId: rid, ParentId: 0, UnionId: c.Id}
attr.UnionId = c.Id needCreate = append(needCreate, newAttr)
} this.attribute[rid] = newAttr
}
} }
} }
} }
// 批量插入缺失的角色属性
if len(needCreate) > 0 {
if _, err := db.MasterDB.Insert(&needCreate); err != nil {
slog.Error("batch insert role attributes error", "error", err)
// 回滚内存中的修改
for _, attr := range needCreate {
delete(this.attribute, attr.RId)
}
} else {
slog.Info("batch inserted role attributes", "count", len(needCreate))
}
}
}
func (this *roleAttributeMgr) Get(rid int) (*model.RoleAttribute, bool) { func (this *roleAttributeMgr) Get(rid int) (*model.RoleAttribute, bool) {
@@ -82,7 +96,6 @@ func (this*roleAttributeMgr) create(rid int) *model.RoleAttribute {
} }
} }
func (this *roleAttributeMgr) IsHasUnion(rid int) bool { func (this *roleAttributeMgr) IsHasUnion(rid int) bool {
this.mutex.RLock() this.mutex.RLock()
@@ -118,4 +131,3 @@ func (this*roleAttributeMgr) List() []*model.RoleAttribute {
} }
return ret return ret
} }

View File

@@ -45,8 +45,11 @@ func (this *roleBuildMgr) Load() {
db.MasterDB.Where("type = ? or type = ?", db.MasterDB.Where("type = ? or type = ?",
model.MapBuildSysCity, model.MapBuildSysCity,
model.MapBuildSysFortress).Delete(new(model.MapRoleBuild)) model.MapBuildSysFortress).Delete(new(model.MapRoleBuild))
for _, sysBuild := range NMMgr.sysBuild {
// 批量插入系统建筑
if len(NMMgr.sysBuild) > 0 {
builds := make([]model.MapRoleBuild, 0, len(NMMgr.sysBuild))
for _, sysBuild := range NMMgr.sysBuild {
build := model.MapRoleBuild{ build := model.MapRoleBuild{
RId: 0, RId: 0,
Type: sysBuild.Type, Type: sysBuild.Type,
@@ -55,7 +58,15 @@ func (this *roleBuildMgr) Load() {
Y: sysBuild.Y, Y: sysBuild.Y,
} }
build.Init() build.Init()
db.MasterDB.InsertOne(&build) builds = append(builds, build)
}
// 批量插入
if _, err := db.MasterDB.Insert(&builds); err != nil {
slog.Error("batch insert system builds error", "error", err)
panic("batch insert error: " + err.Error())
} else {
slog.Info("batch inserted system builds", "count", len(builds))
}
} }
} }
} }
@@ -129,8 +140,32 @@ func (this *roleBuildMgr) CheckGiveUp() []int {
} }
this.giveUpMutex.Unlock() this.giveUpMutex.Unlock()
// 批量处理放弃的土地 - 使用事务
if len(builds) > 0 {
sess := db.MasterDB.NewSession()
defer sess.Close()
if err := sess.Begin(); err != nil {
slog.Warn("begin transaction error", "error", err)
return ret
}
for _, build := range builds { for _, build := range builds {
this.RemoveFromRole(build) build.Reset()
if _, err := sess.ID(build.Id).Update(build); err != nil {
slog.Warn("update giveup build error", "id", build.Id, "error", err)
sess.Rollback()
return ret
}
// 从角色列表移除(仅内存操作)
this.removeFromRoleMemory(build)
}
if err := sess.Commit(); err != nil {
slog.Warn("commit transaction error", "error", err)
} else {
slog.Debug("batch process giveup builds", "count", len(builds))
}
} }
return ret return ret
@@ -154,13 +189,65 @@ func (this *roleBuildMgr) CheckDestroy() []int {
} }
this.destroyMutex.Unlock() this.destroyMutex.Unlock()
// 批量处理拆除的建筑 - 使用事务
if len(builds) > 0 {
sess := db.MasterDB.NewSession()
defer sess.Close()
if err := sess.Begin(); err != nil {
slog.Warn("begin transaction error", "error", err)
return ret
}
for _, build := range builds { for _, build := range builds {
build.ConvertToRes() build.ConvertToRes()
build.SyncExecute() if _, err := sess.ID(build.Id).Update(build); err != nil {
slog.Warn("update destroy build error", "id", build.Id, "error", err)
sess.Rollback()
return ret
}
}
if err := sess.Commit(); err != nil {
slog.Warn("commit transaction error", "error", err)
} else {
slog.Debug("batch process destroy builds", "count", len(builds))
}
} }
return ret return ret
} }
// 辅助函数:从角色内存列表中移除建筑(不涉及数据库)
func (this *roleBuildMgr) removeFromRoleMemory(build *model.MapRoleBuild) {
this.baseMutex.Lock()
rb, ok := this.roleRB[build.RId]
if ok {
for i, v := range rb {
if v.Id == build.Id {
this.roleRB[build.RId] = append(rb[:i], rb[i+1:]...)
break
}
}
}
this.baseMutex.Unlock()
//移除放弃事件
t := build.GiveUpTime
this.giveUpMutex.Lock()
if ms, ok := this.giveUpRB[t]; ok {
delete(ms, build.Id)
}
this.giveUpMutex.Unlock()
//移除拆除事件
t = build.EndTime.Unix()
this.destroyMutex.Lock()
if ms, ok := this.destroyRB[t]; ok {
delete(ms, build.Id)
}
this.destroyMutex.Unlock()
}
/* /*
该位置是否被角色占领 该位置是否被角色占领
*/ */

View File

@@ -57,7 +57,6 @@ func (this*roleResMgr) Load() {
} }
func (this *roleResMgr) Get(rid int) (*model.RoleRes, bool) { func (this *roleResMgr) Get(rid int) (*model.RoleRes, bool) {
this.mutex.RLock() this.mutex.RLock()
@@ -88,7 +87,7 @@ func (this*roleResMgr) Get(rid int) (*model.RoleRes, bool){
} }
} }
func (this*roleResMgr) Add(res *model.RoleRes) (){ func (this *roleResMgr) Add(res *model.RoleRes) {
this.mutex.Lock() this.mutex.Lock()
this.rolesRes[res.RId] = res this.rolesRes[res.RId] = res
@@ -163,8 +162,6 @@ func (this*roleResMgr) TryUseDecree(rid int, decree int) bool{
} }
} }
//金币是否足够 //金币是否足够
func (this *roleResMgr) GoldIsEnough(rid int, cost int) bool { func (this *roleResMgr) GoldIsEnough(rid int, cost int) bool {
@@ -183,7 +180,6 @@ func (this*roleResMgr) GoldIsEnough(rid int, cost int) bool {
} }
} }
func (this *roleResMgr) TryUseGold(rid int, gold int) bool { func (this *roleResMgr) TryUseGold(rid int, gold int) bool {
this.mutex.RLock() this.mutex.RLock()
@@ -203,46 +199,84 @@ func (this*roleResMgr) TryUseGold(rid int, gold int) bool{
} }
} }
func (this *roleResMgr) produce() { func (this *roleResMgr) produce() {
index := 1 index := 1
for true { for true {
t := static_conf.Basic.Role.RecoveryTime t := static_conf.Basic.Role.RecoveryTime
time.Sleep(time.Duration(t) * time.Second) time.Sleep(time.Duration(t) * time.Second)
this.mutex.RLock() this.mutex.RLock()
// 收集需要更新的角色资源
updateList := make([]*model.RoleRes, 0, len(this.rolesRes))
for _, v := range this.rolesRes { for _, v := range this.rolesRes {
//加判断是因为爆仓了,资源不无故减少 //加判断是因为爆仓了,资源不无故减少
capacity := GetDepotCapacity(v.RId) capacity := GetDepotCapacity(v.RId)
yield := GetYield(v.RId) yield := GetYield(v.RId)
needUpdate := false
if v.Wood < capacity { if v.Wood < capacity {
v.Wood += util.MinInt(yield.Wood/6, capacity) v.Wood += util.MinInt(yield.Wood/6, capacity)
needUpdate = true
} }
if v.Iron < capacity { if v.Iron < capacity {
v.Iron += util.MinInt(yield.Iron/6, capacity) v.Iron += util.MinInt(yield.Iron/6, capacity)
needUpdate = true
} }
if v.Stone < capacity { if v.Stone < capacity {
v.Stone += util.MinInt(yield.Stone/6, capacity) v.Stone += util.MinInt(yield.Stone/6, capacity)
needUpdate = true
} }
if v.Grain < capacity { if v.Grain < capacity {
v.Grain += util.MinInt(yield.Grain/6, capacity) v.Grain += util.MinInt(yield.Grain/6, capacity)
needUpdate = true
} }
if v.Gold < capacity { if v.Gold < capacity {
v.Grain += util.MinInt(yield.Grain/6, capacity) v.Gold += util.MinInt(yield.Gold/6, capacity)
needUpdate = true
} }
if index%6 == 0 { if index%6 == 0 {
if v.Decree < static_conf.Basic.Role.DecreeLimit { if v.Decree < static_conf.Basic.Role.DecreeLimit {
v.Decree += 1 v.Decree += 1
} needUpdate = true
}
v.SyncExecute()
}
index++
this.mutex.RUnlock()
} }
} }
if needUpdate {
updateList = append(updateList, v)
}
}
index++
this.mutex.RUnlock()
// 批量更新数据库 - 使用事务
if len(updateList) > 0 {
sess := db.MasterDB.NewSession()
defer sess.Close()
if err := sess.Begin(); err != nil {
slog.Warn("begin transaction error", "error", err)
continue
}
for _, v := range updateList {
if _, err := sess.ID(v.RId).Cols("wood", "iron", "stone", "grain", "gold", "decree").Update(v); err != nil {
slog.Warn("update role res error", "rid", v.RId, "error", err)
sess.Rollback()
goto CONTINUE
}
}
if err := sess.Commit(); err != nil {
slog.Warn("commit transaction error", "error", err)
} else {
slog.Debug("batch update role resources", "count", len(updateList))
}
}
CONTINUE:
}
}