在開發好友系統時, 做了個功能叫做推薦名單, 也就是將最近對戰的玩家記錄到數據表上, 再推給客戶端, 但在獲取數據時發現必須過濾掉已經添加的清單, 索性在表格上添加了一個字段來紀錄是否有效
45883-4ngtcpyj76m.png

後來發現Chloe處理這段很麻煩, 沒查到官方有 replace 的功能, 所以自己用了 procedure 來處理, 有點久沒用研究了下 Chole 怎麼調用

官方文檔說明
https://github.com/shuxinqin/Chloe/wiki/Oracle-procedure
42712-uac01obubl8.png

兩個寫法不一樣, dbContext.SqlQuery 是直接獲取 Procedure 返回數據的, 就譬如 procedure 最後面寫了 select * from user limit 1; 可以透過這個方式獲取返回的 user 資料, 而 ExecuteNonQuery("Proc_GetPersonName", CommandType.StoredProcedure, id, outputName) 則是透過 Procedure 的 out 獲取數據

我們在更新 recent 表格同時也要獲取 recent 數據, 作法如果

DbParam iUserId = new DbParam("@iUserId", userId);
DbParam iRUserId = new DbParam("@iRUserId", recentUserId);
DbParam iState = new DbParam("@iState", 1);
dbContext.SqlQuery<Tbl_Recent>("proc_update_recent", CommandType.StoredProcedure, iUserId, iRUserId, iState);

這是一個沒有 return 的 procedure 調用方式, Procedure 如下

CREATE DEFINER=`root`@`127.0.0.1` PROCEDURE `proc_update_recent`(
    IN `iUserId` int,
    IN `iRUserId` int, 
    IN `iState` int)
BEGIN
    DECLARE ts long;
    set ts = (UNIX_TIMESTAMP() * 1000) + (MICROSECOND(NOW(3)) / 1000);

    REPLACE into `recent`(`UserId` ,`RUserId`, `State`)
        value
    (iUserId, iRUserId, iState);
END

另外得益於使用 Procedure , 在發送邀請功能上需要判斷很多情況, 如果在 c# 處理邏輯就會很繁瑣, 後來使用 Procedure 解決, 如下

CREATE DEFINER=`root`@`127.0.0.1` PROCEDURE `proc_check_send_friendApply`(
    IN `iApplyUserId` BIGINT,
    IN `iApplyUserName` VARCHAR(64),
    IN `iApplyUserHead` VARCHAR(128),
    IN `iToUserId` BIGINT, OUT `oData` INT)
MAINLOOP:BEGIN

    # declare timestamp
    DECLARE ts BIGINT(20) default 0;
    DECLARE isMyFriend TINYINT(4) default 0;
    DECLARE findRecent TINYINT(4) default 0;
    DECLARE findFriend TINYINT(4) default 0;
    DECLARE findApply TINYINT(4) default 0;


    set ts = (UNIX_TIMESTAMP() * 1000) + (MICROSECOND(NOW(3)) / 1000);

    #已經是我的好友, 退出流程
    select count(*) into isMyFriend from `friend` where `UserId`=iApplyUserId and `FUserId`=iToUserId;
    if isMyFriend != 0 then
        LEAVE MAINLOOP;
    end if;

    #if 如果Recent裡面有數據, 就改掉 state = 1
    select count(*) into findRecent from `recent` where `UserId`=iApplyUserId and `RUserId`=iToUserId;
    if findRecent != 0 then
        REPLACE into `recent`(`UserId` ,`RUserId`,`State`) value (iApplyUserId, iToUserId, 1);
    end IF;

    #if 對方已經是好友就直接加回去, 
    select count(*) into findFriend from `friend` where `UserId`=iToUserId and `FUserId`=iApplyUserId;
    if findFriend != 0 then
        REPLACE into `friend`(`UserId` ,`FUserId`,`CreateTime`, `UpdateTime`) value (iApplyUserId, iToUserId, ts, ts);
        set oData = 2;
        LEAVE MAINLOOP;
    end if;

    #如果沒有邀請過就發邀請
    select count(*) into findApply from `friendapply` where `ApplyUserId`=iApplyUserId and `ToUserId`=iToUserId;
    if findApply = 0 then
        REPLACE into `friendapply`(`ApplyUserId` ,`ApplyUserName`, `ApplyUserHead`, `ToUserId`, `State`, `CreateTime`, `UpdateTime`)
        value
        (iApplyUserId, iApplyUserName, iApplyUserHead, iToUserId, 0, ts, 0);

        select * from `friendapply` where `ApplyUserId`=iApplyUserId and `ToUserId`=iToUserId limit 1;
        set oData = 1;
    end if;
END

很久以前在做第一版的麻將時發現那位服務端非常喜歡用存儲過程, 可能是因為服務端 nodejs 且沒有做數據持久化的緣故, 很多數據無法獲取必須重新拉數據, 這樣就會造成數據庫壓力很大, 最早接手開發RPG遊戲時必然是必須做數據持久化的, 設計到服務端乘載人數跟架構, 不做數據持久化管理壓力會壓在Mysql上, 後來做博奕遊戲就很少做這塊了, 輕便為主

标签: none

添加新评论