2.6.C++项目:网络版五子棋对战之数据管理模块-游戏房间管理模块的设计

news2024/11/16 13:37:58

在这里插入图片描述

文章目录

  • 一、意义
  • 二、功能
  • 三、作用
  • 四、游戏房间类基本框架
  • 五、游戏房间管理类基本框架
  • 七、游戏房间类代码
  • 八、游戏房间管理类代码

一、意义

对匹配成功的玩家创建房间,建立起一个小范围的玩家之间的关联关系!
房间里一个玩家产生的动作将会广播给房间里的其他用户。

二、功能

将这些房间管理起来,以便于进行房间生命周期的控制!

三、作用

  • 游戏房间类:
    // 实现两个部分:
    // 1. 房间的设计
    // 2. 房间管理的设置
    // 游戏房间的设计:
    // 管理的数据,处理房间中产生的动作
    // 1. 房间的ID
    // 2. 房间的状态(决定了一个玩家退出房间时所作的动作)
    // 3. 房间中玩家的数量(决定了玩家什么时候销毁)
    // 4. 白棋玩家id
    // 5. 黑棋玩家id
    // 6. 用户信息表的句柄(当玩家胜利/失败的时候更新用户数据)
    // 7. 棋盘信息(二维数组)
    // 房间中产生的动作:
    // 1. 下棋
    // 2. 聊天
    // 不管是什么动作,只要是合理的,都要广播给房间里的其他用户!
  • 游戏房间管理类:
    // Restful 风格的网络通信接口设计:
    // 房间管理:
    // 1. 创建房间 (两个玩家对战匹配完成了,为他们创造一个房间,需要传入两个玩家的用户id)
    // 2. 查找房间 (通过房间id查找房间信息,通过用户id查找房间所在信息)
    // 3. 销毁房间 (根据房间id销毁房间,房间中所有用户退出了,销毁房间)
    // 需要管理的数据:
    // 1. 数据管理模块句柄
    // 2. 在线用户管理模块句柄
    // 3. 房间id分配计数器
    // 4. 互斥锁
    // using room_ptr = std::shared_ptr; 房间信息的空间使用shared_ptr进行管理,释放了我们还操作,访问错误!
    // 5. unordered_map<room_id,room_ptr> 房间信息管理(建立起房间id与房间信息的映射关系)
    // 6. unordered_map<room_id,user_id> 房间id与用户id的关联关系管理! 通过用户id找到所在房间id,再去查找房间信息!
    // 7. 房间中所有用户退出了,销毁房间。

四、游戏房间类基本框架

typedef enum { GAME_START, GAME_OVER }room_statu;
class room {
    private:
    // 1. 房间的ID
    // 2. 房间的状态(决定了一个玩家退出房间时所作的动作)
    // 3. 房间中玩家的数量(决定了玩家什么时候销毁)
    // 4. 白棋玩家id
    // 5. 黑棋玩家id
    // 6. 用户信息表的句柄(当玩家胜利/失败的时候更新用户数据)
    // 7. 棋盘信息(二维数组)
        uint64_t _room_id;
        room_statu _statu;
        int _player_count;
        uint64_t _white_id;
        uint64_t _black_id;
        user_table *_tb_user; 
        online_manager *_online_user;
        std::vector<std::vector<int>> _board;
    public:
        room()
        ~room()
        /*处理下棋动作*/
        room_statu statu();
        int player_count();
        void add_white_user(uint64_t uid);
        void add_black_user(uint64_t uid);
        uint64_t get_white_user();
        uint64_t get_black_user();
        void handle_chess(Json::Value &req);
        /*处理聊天动作*/
        Json::Value handle_chat(Json::Value &req);
        /*处理玩家退出房间动作*/
        void handle_exit(uint64_t uid);
        /*将指定的信息广播给房间中所有玩家*/
        void broadcast(Json::Value &rsp);
};

五、游戏房间管理类基本框架

using room_ptr = std::shared_ptr<room>;

class room_manager {
    private:
    uint64_t _next_rid;
        std::mutex _mutex;
        user_table *_tb_user;
        online_manager *_online_user;
        std::unordered_map<uint64_t, room_ptr> _rooms;
        std::unordered_map<uint64_t, uint64_t> _users;
    room_manager();
    ~room_manager();
    //为两个用户创建房间,并返回房间的智能指针管理对象
    room_ptr create_room(uint64_t uid1, uint64_t uid2);
     /*通过房间ID获取房间信息*/
    room_ptr get_room_by_rid(uint64_t rid);
    /*通过用户ID获取房间信息*/
    room_ptr get_room_by_uid(uint64_t uid);
     /*通过房间ID销毁房间*/
    void remove_room(uint64_t rid);
    /*删除房间中指定用户,如果房间中没有用户了,则销毁房间,用户连接断开时被调用*/
    void remove_room_user(uint64_t uid);
};

七、游戏房间类代码

#ifndef __M_ROOM_H__
#define __M_ROOM_H__
#include "util.hpp"
#include "logger.hpp"
#include "online.hpp"
#include "db.hpp"
#define BOARD_ROW 15
#define BOARD_COL 15
#define CHESS_WHITE 1
#define CHESS_BLACK 2
typedef enum { GAME_START, GAME_OVER }room_statu;
class room {
    private:
    // 1. 房间的ID
    // 2. 房间的状态(决定了一个玩家退出房间时所作的动作)
    // 3. 房间中玩家的数量(决定了玩家什么时候销毁)
    // 4. 白棋玩家id
    // 5. 黑棋玩家id
    // 6. 用户信息表的句柄(当玩家胜利/失败的时候更新用户数据)
    // 7. 棋盘信息(二维数组)
        uint64_t _room_id;
        room_statu _statu;
        int _player_count;
        uint64_t _white_id;
        uint64_t _black_id;
        user_table *_tb_user; 
        online_manager *_online_user;
        std::vector<std::vector<int>> _board;
    private: 
        bool five(int row, int col, int row_off, int col_off, int color) {
            //row和col是下棋位置,  row_off和col_off是偏移量,也是方向
            int count = 1;
            int search_row = row + row_off;
            int search_col = col + col_off;
            while(search_row >= 0 && search_row < BOARD_ROW &&
                  search_col >= 0 && search_col < BOARD_COL &&
                  _board[search_row][search_col] == color) {
                //同色棋子数量++
                count++;
                //检索位置继续向后偏移
                search_row += row_off;
                search_col += col_off;
            }
            search_row = row - row_off;
            search_col = col - col_off;
            while(search_row >= 0 && search_row < BOARD_ROW &&
                  search_col >= 0 && search_col < BOARD_COL &&
                  _board[search_row][search_col] == color) {
                //同色棋子数量++
                count++;
                //检索位置继续向后偏移
                search_row -= row_off;
                search_col -= col_off;
            }
            return (count >= 5);
        }
        uint64_t check_win(int row, int col, int color) {
            // 从下棋位置的四个不同方向上检测是否出现了5个及以上相同颜色的棋子(横行,纵列,正斜,反斜)
            if (five(row, col, 0, 1, color) || 
                five(row, col, 1, 0, color) ||
                five(row, col, -1, 1, color)||
                five(row, col, -1, -1, color)) {
                //任意一个方向上出现了true也就是五星连珠,则设置返回值
                return color == CHESS_WHITE ? _white_id : _black_id;
            }
            return 0;
        }
    public:
        room(uint64_t room_id, user_table *tb_user, online_manager *online_user):
            _room_id(room_id), _statu(GAME_START), _player_count(0),
            _tb_user(tb_user), _online_user(online_user),
            _board(BOARD_ROW, std::vector<int>(BOARD_COL, 0)){
            DLOG("%lu 房间创建成功!!", _room_id);
        }
        ~room() {
            DLOG("%lu 房间销毁成功!!", _room_id);
        }
        uint64_t id() { 
            return _room_id; 
        }
        room_statu statu() { 
            return _statu; 
        }
        int player_count() { 
            return _player_count; 
        }
        void add_white_user(uint64_t uid) { 
            _white_id = uid; _player_count++;
        }
        void add_black_user(uint64_t uid) {
            _black_id = uid; _player_count++; 
        }
        uint64_t get_white_user() { 
            return _white_id; 
        }
        uint64_t get_black_user() { 
            return _black_id; 
        }
        // 处理下棋动作
        Json::Value handle_chess(Json::Value &req) {
            Json::Value json_resp = req;
             // 2. 判断房间中两个玩家是否都在线,任意一个不在线,就是另一方胜利。
            int chess_row = req["row"].asInt();
            int chess_col = req["col"].asInt();
            uint64_t cur_uid = req["uid"].asUInt64();
            if (_online_user -> is_in_game_room(_white_id) == false) {
                json_resp["result"] = true;
                json_resp["reason"] = "运气真好!对方掉线,不战而胜!";
                json_resp["winner"] = (Json::UInt64)_black_id;
                return json_resp;
            }
            if (_online_user->is_in_game_room(_black_id) == false) {
                json_resp["result"] = true;
                json_resp["reason"] = "运气真好!对方掉线,不战而胜!";
                json_resp["winner"] = (Json::UInt64)_white_id;
                return json_resp;
            }
             // 3. 获取走棋位置,判断当前走棋是否合理(位置是否已经被占用)
            if (_board[chess_row][chess_col] != 0) {
                json_resp["result"] = false;
                json_resp["reason"] = "当前位置已经有了其他棋子!";
                return json_resp;
            }
            int cur_color = cur_uid == _white_id ? CHESS_WHITE : CHESS_BLACK;
            _board[chess_row][chess_col] = cur_color;
             // 4. 判断是否有玩家胜利(从当前走棋位置开始判断是否存在五星连珠)
            uint64_t winner_id = check_win(chess_row, chess_col, cur_color);
            if (winner_id != 0) {
                json_resp["reason"] = "五星连珠,您获胜了!";
            }
            json_resp["result"] = true;
            json_resp["winner"] = (Json::UInt64)winner_id;
            return json_resp;
        }
        /*处理聊天动作*/
        Json::Value handle_chat(Json::Value &req) {
            Json::Value json_resp = req;
            // 检查消息中是否包含敏感词
            std::string msg = req["message"].asString();
            size_t pos = msg.find("sb");
            if (pos != std::string::npos) {
                json_resp["result"] = false;
                json_resp["reason"] = "消息中包含敏感词,不能发送!";
                return json_resp;
            }
            //广播消息---返回消息
            json_resp["result"] = true;
            return json_resp;
        }
        /*处理玩家退出房间动作*/
        void handle_exit(uint64_t uid) {
            //如果是下棋中退出,则对方胜利,否则下棋结束了退出,则是正常退出
            Json::Value json_resp;
            if (_statu == GAME_START) {
                uint64_t winner_id = (Json::UInt64)(uid == _white_id ? _black_id : _white_id);
                json_resp["optype"] = "put_chess";
                json_resp["result"] = true;
                json_resp["reason"] = "对方掉线,不战而胜!";
                json_resp["room_id"] = (Json::UInt64)_room_id;
                json_resp["uid"] = (Json::UInt64)uid;
                json_resp["row"] = -1;
                json_resp["col"] = -1;
                json_resp["winner"] = (Json::UInt64)winner_id;
                uint64_t loser_id = winner_id == _white_id ? _black_id : _white_id;
                _tb_user->win(winner_id);
                _tb_user->lose(loser_id);
                _statu = GAME_OVER;
                broadcast(json_resp);
            }
              //房间中玩家数量--
            _player_count--;
            return;
        }
        void handle_request(Json::Value &req) {
            //1. 校验房间号是否匹配
            Json::Value json_resp;
            uint64_t room_id = req["room_id"].asUInt64();
            if (room_id != _room_id) {
                json_resp["optype"] = req["optype"].asString();
                json_resp["result"] = false;
                json_resp["reason"] = "房间号不匹配!";
                return broadcast(json_resp);
            }
            //2. 根据不同的请求类型调用不同的处理函数
             if (req["optype"].asString() == "put_chess") {
                json_resp = handle_chess(req);
                if (json_resp["winner"].asUInt64() != 0) {
                    uint64_t winner_id = json_resp["winner"].asUInt64();
                    uint64_t loser_id = winner_id == _white_id ? _black_id : _white_id;
                    _tb_user->win(winner_id);
                    _tb_user->lose(loser_id);
                    _statu = GAME_OVER;
                }
            }
            else if (req["optype"].asString() == "chat") {
                json_resp = handle_chat(req);
            }
            else {
                json_resp["optype"] = req["optype"].asString();
                json_resp["result"] = false;
                json_resp["reason"] = "未知请求类型";
            }
            std::string body;
            json_util::serialize(json_resp, body);
            DLOG("房间-广播动作: %s", body.c_str());
            return broadcast(json_resp);
        }
        /*将指定的信息广播给房间中所有玩家*/
        void broadcast(Json::Value &rsp) {
            //1. 对要响应的信息进行序列化,将Json::Value中的数据序列化成为json格式字符串
            std::string body;
            json_util::serialize(rsp, body);
            //2. 获取房间中所有用户的通信连接
            //3. 发送响应信息
            wsserver_t::connection_ptr wconn = _online_user->get_conn_from_room(_white_id);
            if (wconn.get() != nullptr) {
                wconn->send(body);
            }
            else {
                DLOG("房间-白棋玩家连接获取失败");
            }
            wsserver_t::connection_ptr bconn = _online_user->get_conn_from_room(_black_id);
            if (bconn.get() != nullptr) {
                bconn->send(body);
            }
            else {
                DLOG("房间-黑棋玩家连接获取失败");
            }
            return;
        }
};

八、游戏房间管理类代码

using room_ptr = std::shared_ptr<room>;

class room_manager {
private:
    uint64_t _next_rid;
        std::mutex _mutex;
        user_table *_tb_user;
        online_manager *_online_user;
        std::unordered_map<uint64_t, room_ptr> _rooms;
        std::unordered_map<uint64_t, uint64_t> _users;
public:
     /*初始化房间ID计数器*/
        room_manager(user_table *ut, online_manager *om):
                _next_rid(1), _tb_user(ut), _online_user(om) {
                DLOG("房间管理模块初始化完毕!");
    }
        ~room_manager() { 
            DLOG("房间管理模块即将销毁!"); 
    }
    //为两个用户创建房间,并返回房间的智能指针管理对象
        room_ptr create_room(uint64_t uid1, uint64_t uid2) {
        // 两个用户在游戏大厅中进行对战匹配,匹配成功后创建房间
        // 1. 校验两个用户是否都还在游戏大厅中,只有都在才需要创建房间。
            if (_online_user->is_in_game_hall(uid1) == false) {
                DLOG("用户:%lu 不在大厅中,创建房间失败!", uid1);
                return room_ptr();
            }
            if (_online_user->is_in_game_hall(uid2) == false) {
                DLOG("用户:%lu 不在大厅中,创建房间失败!", uid2);
                return room_ptr();
            }
        // 2. 创建房间,将用户信息添加到房间中
            std::unique_lock<std::mutex> lock(_mutex);
            room_ptr rp(new room(_next_rid,_tb_user,_online_user));
            rp->add_white_user(uid1);
            rp->add_black_user(uid2);
        //3. 将房间信息管理起来
            _rooms.insert(std::make_pair(_next_rid, rp));
            _users.insert(std::make_pair(uid1, _next_rid));
            _users.insert(std::make_pair(uid2, _next_rid));
            _next_rid++;
        //4. 返回房间信息
            return rp;
    }
    /*通过房间ID获取房间信息*/
        room_ptr get_room_by_rid(uint64_t rid) {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _rooms.find(rid);
            if (it == _rooms.end()) {
                return room_ptr();
            }
            return it->second;
        }
        /*通过用户ID获取房间信息*/
        room_ptr get_room_by_uid(uint64_t uid) {
            std::unique_lock<std::mutex> lock(_mutex);
            //1. 通过用户ID获取房间ID
            auto uit = _users.find(uid);
            if (uit == _users.end()) {
                return room_ptr();
            }
            uint64_t rid = uit->second;
            //2. 通过房间ID获取房间信息
            auto rit = _rooms.find(rid);
            if (rit == _rooms.end()) {
                return room_ptr();
            }
            return rit->second;
        }
  
     /*通过房间ID销毁房间*/
    void remove_room(uint64_t rid) {
        //因为房间信息,是通过shared_ptr在_rooms中进行管理,因此只要将shared_ptr从_rooms中移除
        //则shared_ptr计数器==0,外界没有对房间信息进行操作保存的情况下就会释放
        //1. 通过房间ID,获取房间信息
        room_ptr rp = get_room_by_rid(rid);
        if (rp.get() == nullptr)
            return ;
        //2. 通过房间信息,获取房间中所有用户的ID
            uint64_t uid1 = rp->get_white_user();
            uint64_t uid2 = rp->get_black_user();
        //3. 移除房间管理中的用户信息
            std::unique_lock<std::mutex> lock(_mutex);
            _users.erase(uid1);
            _users.erase(uid2);
            //4. 移除房间管理信息
            _rooms.erase(rid);
    }
    /*删除房间中指定用户,如果房间中没有用户了,则销毁房间,用户连接断开时被调用*/
    void remove_room_user(uint64_t uid) {
        room_ptr rp = get_room_by_rid(uid);
        if (rp.get() == nullptr)
            return ;
        rp->handle_exit(uid);
        if (rp->player_count() == 0) {
            remove_room(rp->id());
        }
        return ;
    }
};

#endif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1125639.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

寻找一罐app里的隐藏海

一、前言 &#xff08;一&#xff09;一罐app简介 一罐app 是一款小众交友软件&#xff0c;可以匿名or真身发布动态 &#xff08;二&#xff09;开发目的 因为某些原因&#xff0c;某些板块被隐藏起来了。&#xff08;一罐称板块为xxx海&#xff09; &#xff08;三&#…

常见面试题-Netty专栏(一)

typora-copy-images-to: imgs Netty 是什么呢&#xff1f;Netty 用于做什么呢&#xff1f; 答&#xff1a; Netty 是一个 NIO 客户服务端框架&#xff0c;可以快速开发网络应用程序&#xff0c;如协议服务端和客户端&#xff0c;极大简化了网络编程&#xff0c;如 TCP 和 UDP …

手搭手Ajax经典基础案例省市联动

环境介绍 技术栈 springbootmybatis-plusmysql 软件 版本 mysql 8 IDEA IntelliJ IDEA 2022.2.1 JDK 1.8 Spring Boot 2.7.13 mybatis-plus 3.5.3.2 pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http:/…

MYSQL(事务+锁+MVCC+SQL执行流程)理解

一)事务的特性: 一致性:主要是在数据层面来说&#xff0c;不能说执行扣减库存的操作的时候用户订单数据却没有生成 原子性:主要是在操作层面来说&#xff0c;要么操作完成&#xff0c;要么操作全部回滚&#xff1b; 隔离性:是自己的事务操作自己的数据&#xff0c;不会受到到其…

有哪些好用的程序员接私活平台?

程序员如何在苦逼的生活中&#xff0c;呼吸一口富贵又自由的空气? 接单的话&#xff0c;如何脱颖而出&#xff1f; 又该用什么平台呢&#xff1f;哪些平台会更靠谱一点呢&#xff1f; 会不会被坑? balabalabalabala......太多问题了&#xff0c;核心还是不了解这里面的详情。…

从理解概念开始,彻底学会linux下的磁盘扩容操作

对于linux磁盘空间不足需要扩容的情况&#xff0c;其他文章一般只介绍要如何操作&#xff0c;使用什么样的命令&#xff0c;但是不去介绍为什么要这么做&#xff0c;搞得好多小白一头雾水。本文从linux的文件系统开始讲起&#xff0c;帮你彻底学会linux系统中的磁盘扩容操作。 …

科学指南针iThenticate自助查重系统重磅上线

科学指南针&#xff0c;一直致力于为科研工作者提供高效、专业的学术支持&#xff0c;近日推出了全新的iThenticate自助查重系统。这一系统的上线&#xff0c;旨在为广大科研工作者提供更加便捷、准确的论文查重服务&#xff0c;进一步规范英文使用&#xff0c;提升科研质量。 …

使用Packstack安装器安装一体化OpenStack云平台

【实训目的】 初步掌握OpenStack快捷安装的方法。掌握OpenStack图形界面的基本操作。 【实训准备】 &#xff08;1&#xff09;准备一台能够安装OpenStack的实验用计算机&#xff0c;建议使用VMware虚拟机。 &#xff08;2&#xff09;该计算机应安装CentOS 7&#xff0c;建…

【网络协议】聊聊网络路由相关算法

如何配置路由 路由器是一台网络设备&#xff0c;多张网卡&#xff0c;当一个入口的网络包到达路由器时&#xff0c;会根据本地的信息库决定如何正确的转发流量&#xff0c;通常称为路由表 路由表主要包含如下 核心思想是根据目的 IP 地址来配置路由 目的网络&#xff1a;要去…

电影评分数据分析案例-Spark SQL

# cording:utf8from pyspark.sql import SparkSession from pyspark.sql.types import IntegerType, StringType, StructType import pyspark.sql.functions as Fif __name__ __main__:# 0.构建执行环境入口对象SparkSessionspark SparkSession.builder.\appName(movie_demo)…

DDOS直接攻击系统资源

DDOS ——直接攻击系统资源 思路&#xff1a; 攻击机利用三次握手机制&#xff0c;产生大量半连接&#xff0c;挤占受害者系统资源&#xff0c;使其无法正常提供服务。 1、先体验下受害者的正常网速。在受害者主机上执行以下命令 (1)开启Apache。 systemctl start apache2 (2…

C++数据结构X篇_20_选择排序

文章目录 1. 选择排序原理2. 选择排序原理核心代码3. 选择排序时间消耗 1. 选择排序原理 选择排序&#xff1a;相对于冒泡排序&#xff0c;减少了交换次数&#xff0c;下图展示了选择排序的原理&#xff0c;具体仍需要结合代码分析。 2. 选择排序原理核心代码 //选择排序 v…

运行报错(三)git bash报错fatal: detected dubious ownership in repository at

报错现象 在运行git 命令时&#xff0c;出现报错 “fatal: detected dubious ownership in repository at” 报错原因 文件夹的所有者和现在的用户不一致 栗子&#xff1a; 文件夹的所有者是root&#xff0c;而当前用户是admin 解决方案 方法一、 将文件夹的所有者替换成ad…

九章云极DataCanvas公司入选Forrester AI/ML权威报告

日前&#xff0c;全球研究机构Forrester最新发布了《The Forrester Wave™: AI/ML Platforms In China, Q4 2023》报告&#xff08;以下简称“报告”&#xff09;。凭借DataCanvas APS机器学习平台这一人工智能核心基础软件的持续研发和广泛应用&#xff0c;九章云极DataCanvas…

数据集-特征降维

1、降维 降维是指在某些限定条件下&#xff0c;降低随机变量(特征)个数&#xff0c;得到一组“不相关”主变量的过程 降低随机变量的个数 相关特征(correlated feature) 相对湿度与降雨量之间的相关等等 正是因为在进行训练的时候&#xff0c;我们都是使用特征进行学习。如果…

基于 Android 的文件同步设计方案

1、背景 随着用户对自身数据保护意识的加强&#xff0c;让用户自己维护自己的数据也成了独立开发产品时的一个卖点。若只针对少量的文件进行同步&#xff0c;则实现起来比较简单。当针对一个多层级目录同步时&#xff0c;情况就复杂多了。鉴于相关的文章甚少&#xff0c;本文我…

MODIS数据产品预处理方法

1 MCTK重投影 第一步&#xff1a;安装ENVI的MCTK扩展工具 解压压缩包&#xff0c;将其中的mctk.sav与modis_products.scsv文件复制到如图所示&#xff0c;相应的ENVI安装路径中去。 第二步&#xff1a;打开ENVI5.3标准版如图所示 在右边的工具栏处打开最下方的Extensions工具…

代码随想录笔记--单调栈篇

1--单调栈 使用单调栈的特征&#xff1a;寻找第一个比当前元素大或者小的元素。 2--每日温度 主要思路&#xff1a; 基于单调栈&#xff0c;单调栈从栈顶开始递增&#xff1b;单调栈存储的是元素对应的索引。 当遇到一个元素大于栈顶元素i时&#xff0c;计算 answer[i]。 #incl…

腾讯待办关停之后还能用吗?可替代的待办提醒APP

如果你之前喜欢用“腾讯待办”这款微信小程序设置待办提醒&#xff0c;那么接下来不得不面对一个事实&#xff1a;腾讯待办将于2023年的12月20日全面停止运营并下架。如果在这款小程序中记录了很多的待办事项&#xff0c;现在应该尽快导出数据&#xff0c;避免数据丢失。 还有…

Rowset Class

Rowset类在PeopleCode中非常常见&#xff0c;以下将Rowset翻译成行集&#xff0c;顾名思义&#xff0c;行的集合 目录 Understanding Rowset Class Shortcut Considerations Data Type of a Rowset Object Scope of a Rowset Object Rowset Class Built-In Functions Row…