负载均衡在线oj(数据库版)

完整网站展示

文件版出发,完善其功能。

创建用户

首先我们需要创建一个用户用来连接数据库:

sql 复制代码
mysql> create user 'oj_client'@'%' identified by '123456';
Query OK, 0 rows affected (0.00 sec)

然后创建数据库:

sql 复制代码
mysql> create database oj;
Query OK, 1 row affected (0.01 sec)

最后授权给新用户:

sql 复制代码
mysql> grant all on oj.* to 'oj_client'@'%';
Query OK, 0 rows affected (0.00 sec)

我们试着用新用户登录,看看是否能看到oj数据库:

看来是没有问题了。

表结构设计

我们利用workbench来完成表结构的设计。

随后根据之前的描述文件,完成对表结构的设计:

据此开始设计:

录入部分题目

为了方便测试,我们先录入部分题目

执行select * from oj_questions;后,点击Form Editor即可开始插入数据。

我们将第一第二题插入:

选中Apply,即可插入。

我们可以从数据库看看是否成功插入:

sql 复制代码
mysql> select * from oj_questions\G
*************************** 1. row ***************************
   number: 1
    title: 判断回文数 
     star: 简单
     desc: 给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。

回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。

例如,121 是回文,而 123 不是。
 

示例 1:

输入:x = 121
输出:true
示例 2:

输入:x = -121
输出:false
解释:从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。
示例 3:

输入:x = 10
输出:false
解释:从右向左读, 为 01 。因此它不是一个回文数。

进阶:你能不将整数转为字符串来解决这个问题吗?
   header: #include <iostream>
#include <string>
#include <vector>
#include <map>
#include <algorithm>

using namespace std;

class Solution
{
public:
    bool isPalindrome(int x)
    {
        return true;
    }
};
     tail: #ifndef COMPILER_ONLINE
#include "header.cpp"
#endif

void Test1()
{
    //匿名对象调用方法
    bool ret=Solution().isPalindrome(121);
    if(ret)
    {
        std::cout<<"通过用例1"<<std::endl;
    }
    else
    {
        std::cout<<"未通过用例1:"<<121<<std::endl;
    }
}

void Test2()
{
    bool ret=Solution().isPalindrome(-19);
    if(!ret)
    {
        std::cout<<"通过用例2"<<std::endl;
    }
    else
    {
        std::cout<<"未通过用例2:"<<-19<<std::endl;
    }
}

int main()
{
    Test1();
    Test2();
    return 0;
}
cpu_limit: 1
mem_limit: 30000
1 row in set (0.00 sec)

没有问题!

继续把第二题页插入:

sql 复制代码
mysql> select * from oj_questions where number=2\G
*************************** 1. row ***************************
   number: 2
    title: 求最大值
     star: 简单
     desc: 求最大值,比如:vector v ={1,2,3,4,5,6,12,3,4,-1};
求最大值, 比如:输出 12
   header: #include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

class Solution
{
public:
    int Max(const vector<int> &v)
    {
        //将你的代码写在下面

        return 0;
    }
};
     tail: #ifndef COMPILER_ONLINE
#include "header.cpp"
#endif

void Test1()
{
    vector<int> v = {1, 2, 3, 4, 5, 6};
    int max = Solution().Max(v);
    if (max == 6)
    {
        std::cout << "Test 1 .... OK" << std::endl;
    }
    else
    {
        std::cout << "Test 1 .... Failed" << std::endl;
    }
}

void Test2()
{
    vector<int> v = {-1, -2, -3, -4, -5, -6};
    int max = Solution().Max(v);
    if (max == -1)
    {
        std::cout << "Test 2 .... OK" << std::endl;
    }
    else
    {
        std::cout << "Test 2 .... Failed" << std::endl;
    }
}

int main()
{
    Test1();
    Test2();

    return 0;
}
cpu_limit: 1
mem_limit: 30000
1 row in set (0.00 sec)

oj_model数据库版设计

由于我们之前是基于MVC结构设计的:

MVC 是一种软件架构模式,核心是把系统分成 3 个部分:

Model(模型):负责数据和业务逻辑(比如代码的编译 / 运行、用户数据存储);

View(视图):负责展示界面(比如用户提交代码的网页、结果展示页面);

Controller(控制器):负责接收用户请求,调用 Model 处理,再把结果传给 View 展示。

那么只需要更改model板块即可。

并且我们保持model接口参数不变,修改其内部实现就可以完成从文件到数据库的转变。这就是解耦的好处啊。

我们先看看原本的Model有什么成员函数:

cpp 复制代码
 class Model
{
private:
    bool LoadAllQuestion(const std::string &question_list);
public:
		Model();
		bool GetAllQuestion(std::vector<Question> *out);
		bool GetOneQuestion(const std::string &number, Question *out);
		~Model() {};
private:
		std::unordered_map<std::string, Question> _questions;
};

显然我们不再需要加载全部题目,因为题目就在数据库中,只需连接数据库。

所以我们能将载入题目、构造函数、析构函数都去掉。

最终结构:

cpp 复制代码
const std::string oj_questions = "oj_questions";
class Model
{
public:
    bool QueryMysql(const std::string &sql, std::vector<Question> *out)
    {
    }
    bool GetAllQuestion(std::vector<Question> *out)
    {
        std::string sql = "select * from ";
        sql += oj_questions;
        return QueryMysql(sql, out);
    }
    bool GetOneQuestion(const std::string &number, Question *out)
    {
        bool res = false;
        std::string sql = "select * from ";
        sql += oj_questions;
        sql += " where number=";
        sql += number;
        std::vector<Question> result;
        if (QueryMysql(sql, &result))
        {
            if (result.size() == 1)
            {
                *out = result[0];
                res = true;
            }
        }
        return res;
    }
};

QueryMysql实现

要实现QueryMysql必须有Mysql的连接库,可以参考我的MySQL用C/C++连接进行下载,然后学习基本接口使用。

记得include头文件:

接下来获取数据的时候要对照建表的顺序获取:

cpp 复制代码
const std::string oj_questions = "oj_questions";
const std::string host = "127.0.0.1";
const std::string user = "oj_client";
const std::string password = "123456";
const std::string db = "oj";
const int port = 3306;
bool QueryMysql(const std::string &sql, std::vector<Question> *out)
{
    // 初始化句柄
    MYSQL *mysql = mysql_init(nullptr);
    // 连接数据库
    if (mysql_real_connect(mysql, host.c_str(), user.c_str(), password.c_str(), db.c_str(), port, nullptr, 0) == nullptr)
    {
        LOG(FATAL) << "连接数据库失败\n";
        return false;
    }
    // 设置编码格式,确保无误
    mysql_set_character_set(mysql, "utf8mb4");

    LOG(INFO) << "连接数据库成功!\n";

    // 执行sql语句
    if (mysql_query(mysql, sql.c_str()) != 0)
    {
        LOG(WARNING) << sql << " execute error!\n";
        return false;
    }

    // 提取结果
    MYSQL_RES *res = mysql_store_result(mysql);

    int rows = mysql_num_rows(res);

    Question q;

    for (int i = 0; i < rows; i++)
    {
        MYSQL_ROW line = mysql_fetch_row(res);
        q.number = line[0];
        q.name = line[1];
        q.star = line[2];
        q.desc = line[3];
        q.header = line[4];
        q.tail = line[5];
        q.cpu_limit = atoi(line[6]);
        q.mem_limit = atoi(line[7]);

        out->push_back(q);
    }

    // 释放结果
    mysql_free_result(res);
    // 关闭连接
    mysql_close(mysql);

    return true;
}

注意我的数据库默认配置字符集是utf8mb4,因此设置字符集为utf8mb4,如果是utf8,应当设置为utf8mb3.

最后将之前包含的文件版头文件,改为数据库版头文件:

综合测试

编译后运行oj服务和编译服务:

测试网站功能:

没有乱码。

提交正常。

项目拓展方向

我们的项目自然可以像leetcode一样拓展许多功能,这里提供一些方向:

  1. 基于注册和登录的录题功能
  2. 业务拓展,如接入论坛
  3. 可以将compiler部署到docker上
  4. 目前的compiler服务是http请求,可以将其设计成远程过程调用,推荐使用rest_rpc
  5. 继续完善功能,如增加测试用例,增加题目
  6. 其他

补充顶层makefile发布项目

我们来编写一个makefile,能直接生成发布版本的文件夹:

bash 复制代码
.PHONY: all
all:
	@cd compile_server;\
	make;\
	cd -;\
	cd oj_server;\
	make;\
	cd -;

.PHONY:output
output:
	@mkdir -p output/compile_server;\
	mkdir -p output/oj_server;\
	cp -rf compile_server/compile_server output/compile_server;\
	cp -rf compile_server/temp output/compile_server;\
	cp -rf oj_server/conf output/oj_server/;\
	cp -rf oj_server/questions output/oj_server/;\
	cp -rf oj_server/template output/oj_server/;\
	cp -rf oj_server/wwwroot output/oj_server/;\
	cp -rf oj_server/oj_server output/oj_server/;

.PHONY:clean
clean:
	@cd compile_server;\
	make clean;\
	cd -;\
	cd oj_server;\
	make clean;\
	cd -;\
	rm -rf output;

完整代码

最后将数据库也打包成sql文件,放到仓库

相关推荐
sunxunyong5 小时前
CGroup配置
linux·运维·服务器
小吴编程之路5 小时前
MySQL 索引核心特性深度解析:从底层原理到实操应用
数据库·mysql
hy____1236 小时前
Linux_网络编程套接字
linux·运维·网络
~莫子6 小时前
MySQL集群技术
数据库·mysql
凤山老林6 小时前
SpringBoot 使用 H2 文本数据库构建轻量级应用
java·数据库·spring boot·后端
就不掉头发6 小时前
Linux与数据库进阶
数据库
与衫6 小时前
Gudu SQL Omni 技术深度解析
数据库·sql
小夏卷编程6 小时前
Ubuntu 20.04.4 宝塔 docker showdoc v3.2 更新到v3.7.3
运维·docker·容器
康康的AI博客6 小时前
农业工业变革:如何通过DMXAPI中转提升自动化效率
运维·人工智能·自动化
咖啡の猫6 小时前
Redis桌面客户端
数据库·redis·缓存