C++项目:在线五子棋对战网页版--数据模块开发

2023-10-13 11:31:19 浏览数 (1)

数据模块开发设计 

数据管理模块,基于mysql数据库进行数据管理以及封装数据管理模块实现数据库访问。因此,在数据库中,我需要为每一张表创建出对应类,通过类实例化的对象来访问这张数据库表中的数 据,这样的话当我们要访问哪张表的时候,使⽤哪个类实例化的对象即可。

那么在五子棋对战项目当中,数据库表只有一张user表,因此我只需要为user表创建一个类即可。

在user类中,该类的作用是通过数据库接口去管理用户数据,因此需要实现的方法:

select_by_name:根据用户名查找用户信息,用于实现登录功能 select_by_id:根据用户id查找用户信息 loser:给失败玩家修改分数 win:给胜利玩家修改分数 insert:注册用户时将用户数据插入到数据库智能 login:登录验证,获取完整的用户信息

接下来是代码的实现

成员变量

由于是对数据库进行操作,因此需要用到MySQL的操作句柄,而且在进行对数据库数据操作的时候,需要添加互斥锁,因此需要用到mutex。

因此,成员变量为MySQL操作句柄以及互斥锁。

代码语言:javascript复制
class user_table
{
private:
    MYSQL* _mysql;//MySQL数据库操作句柄
    std::mutex _mutex;//互斥锁
public:
        /*.....*/
};

成员函数

成员函数即上述所说的六个方法,以及构造方法和析构方法。

代码语言:javascript复制
    /*通过用户名获取用户信息*/
    /*返回值为bool,判断是否成功获取,参数username为用户名,输出型参数user用于保存获取到的用户数据*/
    bool select_by_name(const std::string& username,Json::Value& user);

    /*通过用户id获取用户信息*/
    /*返回值为bool,判断是否成功获取,参数id为用户id,输出型参数user用于保存获取到的用户数据*/
    bool select_by_id(uint16_t id,Json::Value& user);

    /*insert:用户注册时,将用户的数据插入到表中,即可注册成功*/
    bool insert(Json::Value& user);

    /*登录验证,并获取用户信息*/
    bool login(Json::Value& user);

    /*胜利时修改分数,传入胜利玩家的id,通过id查找出对应的数据并进行修改*/
    bool win(uint16_t id);

    /*失败时修改分数,传入失败玩家的id,通过id查找出对应的数据并进行修改*/
    bool loser(uint16_t id);

代码实现

①构造方法

我首先需要获取MySQL数据库的操作句柄,并且连接到MySQL的服务器中,将MySQL数据库的字符集设置成utf8,因此,在构造方法中,参数有MySQL数据库服务器的地址host、MySQL数据库的用户名、密码、数据库名称、端口号。

代码语言:javascript复制
    user_table(
            const std::string& host,
            const std::string& username,
            const std::string& password,
            const std::string& dbname,
            uint16_t port = 3306)
    {
        _mysql = mysql_util::mysql_create(host,username,password,dbname,port);
        assert(_mysql!=nullptr);
    }
②析构方法

调用销毁句柄的方法即可;

代码语言:javascript复制
    ~user_table()
    {
        mysql_util::mysql_destory(_mysql);
        _mysql==nullptr;
    }
③通过用户名获取用户信息的方法

返回值为bool,判断是否成功获取,参数username为用户名,输出型参数user用于保存获取到的用户数据。

流程:

1.先定义出MySQL的查询语句的字符串,将其保存到字符数组sql中。

2.我们需要对操作进行互斥锁,保护起来,以免其它线程进行了数据的修改。因此,划出一段空间出来,形成互斥锁的生命周期。

3.进行语句查询,查询后,获取结果集保存到本地,如果获取失败,则说明没有该用户,如果有,那么往下走。

4.获取结果集的行数,然后遍历结果集,将该用户的数据填入user中,返回回去。

5.最后释放结果集。

代码语言:javascript复制
bool select_by_name(const std::string& username,Json::Value& user)
    {
        #define USER_BY_NAME "select id,score,total_count,win_count from user where username='%s';"
        char sql[4096]={0};
        sprintf(sql,USER_BY_NAME,username.c_str());/*将查询表的字符串写入到sql中*/
        /*MYSQL_RES保存查询结果到本地:mysql_store_resul(_mysql)*/
        MYSQL_RES* res=NULL;
        /*查询操作需要使用互斥锁进行保护*/
        {
            std::unique_lock<std::mutex> lock(_mutex);
            bool ret = mysql_util::mysql_exec(_mysql,sql);//执行查询语句
            if(ret==false)
            {
                DLOG("user select_by_name failed!!n");
                return false;
            }
            //查询成功,将查询结果保存到本地
            res = mysql_store_result(_mysql);
            if(res==NULL)
            {
                DLOG("have no user info!!");
                return false;
            }

        }
        /*保存到本地之后,需要将结果放入到Json::Value user中
        因此,先获取到结果集的行数,然后遍历结果集,将其放入user中*/
        /*获取结果集的行数*/
        int row_num = mysql_num_rows(res);
        if(row_num!=1)
        {
            DLOG("the user information queried is not unique!");
            return false;
        }
        /*遍历结果集,将数据存储在user中,row是列数噢,row[0]为第0列*/
        MYSQL_ROW row = mysql_fetch_row(res);
        user["id"] = (Json::UInt64)std::stol(row[0]);/*先转化成长整型,然后转化成json形式的无符号整型*/
        user["username"] = username;
        user["score"] = (Json::UInt64)std::stol(row[1]);
        user["total_count"] = std::stoi(row[2]);
        user["win_count"] = std::stoi(row[3]);
        mysql_free_result(res);
        return true;
    }
④通过用户id获取用户信息

返回值为bool,判断是否成功获取,参数id为用户id,输出型参数user用于保存获取到的用户数据。

流程:

1.先定义出MySQL的查询语句的字符串,将其保存到字符数组sql中。

2.我们需要对操作进行互斥锁,保护起来,以免其它线程进行了数据的修改。因此,划出一段空间出来,形成互斥锁的生命周期。

3.进行语句查询,查询后,获取结果集保存到本地,如果获取失败,则说明没有该用户,如果有,那么往下走。

4.获取结果集的行数,然后遍历结果集,将该用户的数据填入user中,返回回去。

5.最后释放结果集。

代码语言:javascript复制
bool select_by_id(uint16_t id,Json::Value& user)
    {
        #define USER_BY_ID "select username,score,total_count,win_count from user where id='%d';"
        char sql[4096]={0};
        sprintf(sql,USER_BY_ID,id);/*将查询表的字符串写入到sql中*/
        /*MYSQL_RES保存查询结果到本地:mysql_store_resul(_mysql)*/
        MYSQL_RES *res=NULL;
        /*查询操作需要使用互斥锁进行保护*/
        {
            std::unique_lock<std::mutex> lock(_mutex);
            bool ret = mysql_util::mysql_exec(_mysql,sql);//执行查询语句
            if(ret==false)
            {
                DLOG("user select_by_name failed!!n");
                return false;
            }
            //查询成功,将查询结果保存到本地
            res = mysql_store_result(_mysql);
            if(res==NULL)
            {
                DLOG("have no user info!!");
                return false;
            }

        }
        /*保存到本地之后,需要将结果放入到Json::Value user中
        因此,先获取到结果集的行数,然后遍历结果集,将其放入user中*/
        /*获取结果集的行数*/
        int row_num = mysql_num_rows(res);
        if(row_num!=1)
        {
            DLOG("the user information queried is not unique!");
            return false;
        }
        /*遍历结果集,将数据存储在user中,row是列数噢,row[0]为第0列*/
        MYSQL_ROW row = mysql_fetch_row(res);
        user["id"] = (Json::UInt64)id;;/*化成json形式的无符号整型*/
        user["username"] = row[0];
        user["score"] = (Json::UInt64)std::stol(row[1]);
        user["total_count"] = std::stoi(row[2]);
        user["win_count"] = std::stoi(row[3]);
        mysql_free_result(res);
        return true;
    }
⑤用户注册方法

用户注册,即将用户名和用户的密码插入到数据库中,如果插入成功,即注册成功。在密码插入这一块,需要对密码进行加密。

流程:

1.首先判断传进来的用户的数据是否完整。

2.定义出MySQL的插入语句的字符串。

3.然后将字符串保存到字符数组中

4.然后上锁,接着执行插入语句。

5.成功插入,则注册成功。

代码语言:javascript复制
bool insert(Json::Value& user)
    {
        #define INSERT_USER "insert user values(null,'%s',password('%s'),1000,0,0);"
        /*判断user中的用户数据是否完整*/
        if(user["username"].isNull() || user["password"].isNull())
        {
            DLOG("INPUT PASSWORD OR USERNAME");
            return false;
        }
        /*数据完整,可以进行注册*/
        char sql[4096]={0};
        /*将执行语句的字符串形式放入到sql中*/
        sprintf(sql,INSERT_USER,user["username"].asCString(),user["password"].asCString());
        bool ret = mysql_util::mysql_exec(_mysql,sql);/*执行*/
        if(ret==false)
        {
            ELOG("insert user info failed!!n");
            return false;
        }
        return true;
    }
⑥登录验证方法

流程:

1.首先对传过来的用户数据进行验证,是否具有完整性,不能缺失用户名和密码。

2.接着定义出MySQL的查询语句,目的是,通过查询语句,去查询是否能够通过该用户名和密码查询出结果,而且结果只能由一条。

3.定义出MySQL的查询语句的字符串之后,将其存储在字符数组中。

4.我们需要对操作进行互斥锁,保护起来,以免其它线程进行了数据的修改。因此,划出一段空间出来,形成互斥锁的生命周期。

5.进行语句查询,查询后,获取结果集保存到本地,如果获取失败,则说明没有该用户,因此验证失败。如果由,那么往下走。

6.获取结果集的行数,然后遍历结果集,将该用户的其它数据进行填入,返回回去。

7.最后释放结果集。

代码语言:javascript复制
    bool login(Json::Value& user)
    {
        /*先判断登录的数据是否完整*/
        if(user["password"].isNull() || user["username"].isNull())
        {
            DLOG("INPUT PASSWORD OR USERNAME");
            return false;
        }
        /*以用户名和密码共同作为查询过滤条件,查询到数据则表示用户密码一致,否则错误*/
        #define LOGIN_USER "select id, score, total_count, win_count from user where username='%s' and password=password('%s');"
        char sql[4096]={0};
        sprintf(sql,LOGIN_USER,user["username"].asCString(),user["password"].asCString());
        /*查询语句执行,查看是否有数据,如果有,也只能有一条数据,如果没数据,说明登录验证不通过*/
        /*查看数据,使用保存结果到本地的函数mysql_store_result()*/
        MYSQL_RES* res=NULL;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            bool ret = mysql_util::mysql_exec(_mysql,sql);
            if(ret==false)
            {
                DLOG("user login failed!!n");
                return false;
            }
            res = mysql_store_result(_mysql);
            if(res==NULL)/*没有数据,登录验证失败*/
            {
                DLOG("have no login user info!!");
                return false;
            }
        }
        /*有数据,获取该用户的其它数据:分数、场次等*/
        int row_num = mysql_num_rows(res);
        if(row_num!=1)
        {
            DLOG("the user information queried is not unique!");
            return false;
        }
        MYSQL_ROW row = mysql_fetch_row(res);
        user["id"] = (Json::UInt64)std::stol(row[0]);
        user["score"] = (Json::UInt64)std::stol(row[1]);
        user["total_count"] = std::stoi(row[2]);
        user["win_count"] = std::stoi(row[3]);
        mysql_free_result(res);
        return true;
    }
⑦胜利时修改分数

流程:先定义出MySQL更新语句的字符串,由于是胜利的,因此分数 30,对战总场次 1,胜利场次 1。

将字符串保存到sql数组中,然后上互斥锁,不能让修改数据的时候,有其它线程同时访问,造成数据的错误。

最后执行语句

代码语言:javascript复制
    bool win(uint16_t id)
    {
        #define USER_WIN "update user set score=score 30, total_count=total_count 1, win_count=win_count 1 where id=%d;"
        char sql[4096]={0};
        sprintf(sql,USER_WIN,id);
        std::unique_lock<std::mutex> lock(_mutex);
        bool ret =  mysql_util::mysql_exec(_mysql,sql);
        if(ret==false)
        {
            DLOG("update winner info failed!n");
            return false;
        } 
        return true;
    }
⑧失败时修改分数

流程:先定义出MySQL更新语句的字符串,由于是失败的,因此分数减去30,对战总场次 1。

将字符串保存到sql数组中,然后上互斥锁,不能让修改数据的时候,有其它线程同时访问,造成数据的错误。

最后执行语句。

代码语言:javascript复制
    bool loser(uint16_t id)
    {
        #define USER_LOSER "update user set score=score-30, total_count=total_count 1 where id=%d;"
        char sql[4096]={0};
        sprintf(sql,USER_LOSER,id);
        std::unique_lock<std::mutex> lock(_mutex);
        bool ret =  mysql_util::mysql_exec(_mysql,sql);
        if(ret==false)
        {
            DLOG("update loser info failed!n");
            return false;
        } 
        return true;
    }

0 人点赞