负载均衡在线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文件,放到仓库

相关推荐
木辰風4 小时前
PLSQL自定义自动替换(AutoReplace)
java·数据库·sql
无限码力4 小时前
华为OD技术面真题 - 数据库MySQL - 3
数据库·mysql·华为od·八股文·华为od技术面八股文
heartbeat..4 小时前
Redis 中的锁:核心实现、类型与最佳实践
java·数据库·redis·缓存·并发
Prince-Peng4 小时前
技术架构系列 - 详解Redis
数据结构·数据库·redis·分布式·缓存·中间件·架构
i建模4 小时前
在 Rocky Linux 上安装轻量级的 XFCE 桌面
linux·运维·服务器
虾说羊4 小时前
redis中的哨兵机制
数据库·redis·缓存
_F_y4 小时前
MySQL视图
数据库·mysql
2301_790300964 小时前
Python单元测试(unittest)实战指南
jvm·数据库·python
Data_Journal4 小时前
Scrapy vs. Crawlee —— 哪个更好?!
运维·人工智能·爬虫·媒体·社媒营销
YMWM_4 小时前
不同局域网下登录ubuntu主机
linux·运维·ubuntu