package mysql import ( "context" "database/sql" "google.golang.org/protobuf/proto" roomv1 "hyapp.local/api/proto/room/v1" "hyapp/pkg/appcode" roomservice "hyapp/services/room-service/internal/room/service" ) const ownerCountryRoomExtKey = "owner_country_code" type ownerCountrySnapshotUpdate struct { roomID string roomVersion int64 payload []byte } // RenameOwnerCountryCode 同事务刷新房间当前列表投影和最新快照中的房主国家码。 // command_log 保留房间发生时事实,因此这里明确只碰当前读模型,供后台国家码重命名任务收敛线上展示态。 func (r *Repository) RenameOwnerCountryCode(ctx context.Context, oldCountryCode string, newCountryCode string, nowMS int64) (roomservice.OwnerCountryCodeRenameResult, error) { app := appcode.FromContext(ctx) var result roomservice.OwnerCountryCodeRenameResult tx, err := r.db.BeginTx(ctx, &sql.TxOptions{}) if err != nil { return roomservice.OwnerCountryCodeRenameResult{}, err } defer tx.Rollback() rows, err := tx.QueryContext(ctx, ` SELECT room_id, room_version, payload FROM room_snapshots WHERE app_code = ? FOR UPDATE `, app) if err != nil { return roomservice.OwnerCountryCodeRenameResult{}, err } updates := []ownerCountrySnapshotUpdate{} for rows.Next() { var update ownerCountrySnapshotUpdate if err := rows.Scan(&update.roomID, &update.roomVersion, &update.payload); err != nil { _ = rows.Close() return roomservice.OwnerCountryCodeRenameResult{}, err } var snapshot roomv1.RoomSnapshot if err := proto.Unmarshal(update.payload, &snapshot); err != nil { _ = rows.Close() return roomservice.OwnerCountryCodeRenameResult{}, err } if snapshot.RoomExt == nil || snapshot.RoomExt[ownerCountryRoomExtKey] != oldCountryCode { continue } snapshot.RoomExt[ownerCountryRoomExtKey] = newCountryCode body, err := proto.Marshal(&snapshot) if err != nil { _ = rows.Close() return roomservice.OwnerCountryCodeRenameResult{}, err } update.payload = body updates = append(updates, update) } if err := rows.Close(); err != nil { return roomservice.OwnerCountryCodeRenameResult{}, err } if err := rows.Err(); err != nil { return roomservice.OwnerCountryCodeRenameResult{}, err } listResult, err := tx.ExecContext(ctx, ` UPDATE room_list_entries SET owner_country_code = ?, updated_at_ms = ? WHERE app_code = ? AND owner_country_code = ? `, newCountryCode, nowMS, app, oldCountryCode) if err != nil { return roomservice.OwnerCountryCodeRenameResult{}, err } result.RoomListEntries, _ = listResult.RowsAffected() for _, update := range updates { // room_version 不递增,避免把低频后台投影修复伪装成 Room Cell 状态版本推进。 affected, err := tx.ExecContext(ctx, ` UPDATE room_snapshots SET payload = ?, updated_at_ms = ? WHERE app_code = ? AND room_id = ? AND room_version = ? `, update.payload, nowMS, app, update.roomID, update.roomVersion) if err != nil { return roomservice.OwnerCountryCodeRenameResult{}, err } rowsAffected, _ := affected.RowsAffected() result.RoomSnapshots += rowsAffected } if err := tx.Commit(); err != nil { return roomservice.OwnerCountryCodeRenameResult{}, err } return result, nil }