Java 课程设计:LWZ - Online Judge学生端(数据库设计部分)

数据库设计#

由于 OJ 系统需要存储的数据很多,因此需要有较为全面的数据库设计。首先需要存储用户基本的用户名和密码信息,以及存储用户的类型是老师还是学生。接着为了支持同学的答题,数据库需要存储题目的信息,包括题干和答案等。值得一提的是,一道编程题会有多个测试点,因此编程题需要额外的一张表存储测试点。需要对同学的答案进行记录,需要有表存储不同题型用户的作答情况,同理也需要有一张表存储用户的成绩。在实际情况下教师一般不会一道题一道题地布置,而是一次性布置多道题,以题目集的形式来存储,所以需要表来存储题目集信息。同学加入班级之后,才需要完成自己班上的任务,老师也只能在自己的班级发布任务,因此需要有两张表分别存储班级信息和老师发布的任务信息。最后还需要一张表存储站内短信,数据库的总体设计如下。

用户部分#

users 表#

存储用户基本信息和用户类型。

题目部分#

choice 表#

存储选择题题目的数据。

judgment 表#

存储判断题题目的数据。

编程题存储#

program 表#

存储编程题题目的数据。

testpoint 表#

存储对应编程题的测试点。

subjective#

存储主观题题目的数据。

collections 表#

存储题目集里有哪些题目。

作答记录部分#

codes 表#

存储用户提交的代码和答题状态。

answer 表#

存储用户主观题作答的答案。

score 表#

存储用户对应题目集的得分情况。

班级管理部分#

classes 表#

存储老师创建的班级和同学加入的班级。

task 表#

存储对应班级要完成的题目集。

站内短信部分#

emails 表#

存储用户发送的站内短信。

数据库读写#

对数据库的读写采用 DAO 模式实现,DAO (DataAccessobjects) 数据存取对象是指位于业务逻辑和持久化数据之间,实现对持久化数据的访问的工作模式,具体可以参考博客:Java DAO 模式。在服务器实现了 3 个 DAO 模式接口,来支持裁判机的正常工作。

CodeRepositoryDAO 接口#

CodeRepository 接口指定了向存储层进行代码数据交互的方法,代码和 UML 类图如下。

Copy Highlighter-hljs
/** * CodeRepositoryDAO 接口指定了向存储层进行代码数据交互的方法 * @author 乌漆 WhiteMoon * @version 1.0 */ public interface CodeRepositoryDAO { /** * 该方法用于将向存储层提交某位同学的某道题的代码 * @param username 提交用户,String * @param id 题目编号,Integer * @param code 代码,String * @param state 解题状态 * @return boolean:提交成功返回true,失败返回false * @throws SQLException */ public boolean submitCode(String username, Integer id , String code, Integer state) throws SQLException; /** * 该方法用于将在存储层查找题目是否提提交过 * @param username 提交用户,String * @param id 题目编号,Integer * @param state 解题状态 * @return boolean:已存在返回true,不存在返回false * @throws SQLException */ public boolean selectCode(String username, Integer id) throws SQLException; /** * 该方法用于将向存储层更新某位同学的某道题的代码 * @param username 提交用户,String * @param id 题目编号,Integer * @param code 代码,String * @param state 解题状态 * @return boolean:提交成功返回true,失败返回false * @throws SQLException */ public boolean updateCode(String username, Integer id , String code, Integer state) throws SQLException; /** * 该方法用于返回数据库中对应题目的所有代码样本 * @param id 题目编号,Integer * @return List<String>:存储所有代码的List集合 * @throws SQLException */ public List<String> selectAllCode(Integer id) throws SQLException; }

PointRepositoryDAO 接口#

PointRepositoryDAO 接口指定了从数据库获取测试点、题目题号和选择判断题答案数据的方法,代码和 UML 类图如下。

Copy Highlighter-hljs
/** * PointRepositoryDAO 接口指定了从数据库获取测试点数据的方法 * @author 林智凯 * @version 1.0 */ public interface PointRepositoryDAO { /** * 该方法用于将从存储层返回对应题目的测试点 * @param num 题目编号,Integer * @return LinkedList<Testpoint>:List集合,存储对应题目的所有测试点: * @throws SQLException */ public List<Testpoint> getTestpoint(Integer num) throws SQLException; /** * 该方法用于将从存储层返回对应题目集包含的所有选择题题号 * @param num 题目集编号,Integer * @return List<Integer>:List集合,存储对应题目集包含的所有选择题号 * @throws SQLException */ public List<Integer> getChoiceNum(Integer num) throws SQLException; /** * 该方法用于将从存储层返回对应题目集包含的所有判断题题号 * @param num 题目集编号,Integer * @return List<Integer>:List集合,存储对应题目集包含的所有判断题号 * @throws SQLException */ public List<Integer> getJudgmentNum(Integer num) throws SQLException; /** * 该方法用于将从存储层返回对应题目集包含的所有编程题题号 * @param num 题目集编号,Integer * @return List<Integer>:List集合,存储对应题目集包含的所有编程题号 * @throws SQLException */ public List<Integer> getProgrammtNum(Integer num) throws SQLException; /** * 该方法用于将从存储层返回对应选择题的答案 * @param choiceNum List<Integer>题目集包含的所有选择题题号 * @return List<String>:List集合,存储对应题号对应的答案 * @throws SQLException */ public List<String> getChoiceAnswer(List<Integer> choiceNum) throws SQLException; /** * 该方法用于将从存储层返回对应判断题的答案 * @param judgmentNum List<Integer>题目集包含的所有选择题题号 * @return List<Integer>:List集合,存储对应题号对应的答案 * @throws SQLException */ public List<String> getJudgmentAnswer(List<Integer> judgmentNum) throws SQLException; }

ScoreRepositoryDAO 接口#

ScoreRepositoryDAO 接口指定了访问修改存储层中同学作答情况和更新分数的方法,代码和 UML 类图如下。

Copy Highlighter-hljs
/** * ScoreRepositoryDAO 接口指定了修改存储层中同学分数的方法 * @author 林智凯 * @version 1.0 */ public interface ScoreRepositoryDAO { /** * 该方法根据用户的信息,更新题目集的选择题分数 * @param username String 用户名 * @param collectionId Integer 题目集id * @param classId String 班级名 * @param grade Integer * @return boolean true为更新成功,false为更新失败 * @throws SQLException */ public boolean updateChoiceScore(String username, Integer collectionId, String classId, Integer grade) throws SQLException; /** * 该方法根据用户的信息,更新题目集的判断题题分数 * @param username String 用户名 * @param collectionId Integer 题目集id * @param classId String 班级名 * @param grade Integer 成绩 * @return boolean true为更新成功,false为更新失败 * @throws SQLException */ public boolean updateJudgmentScore(String username, Integer collectionId, String classId, Integer grade) throws SQLException; /** * 该方法根据用户的信息,更新题目集的编程题题分数 * @param username String 用户名 * @param collectionId Integer 题目集id * @param classId String 班级名 * @param grade Integer 成绩 * @return boolean true为更新成功,false为更新失败 * @throws SQLException */ public boolean updateProgrammingScore(String username, Integer collectionId, String classId, Integer grade) throws SQLException; /** * 该方法实现搜索对应题目集的选择题总分 * @param collectionId Integer 题目集id * @return Integer 题目集选择题总分 * @throws SQLException */ public Integer getChoiceScore(Integer collectionId) throws SQLException; /** * 该方法实现搜索对应题目集的判断题总分 * @param collectionId Integer 题目集id * @return Integer 题目集判断题总分 * @throws SQLException */ public Integer getJudgmentScore(Integer collectionId) throws SQLException; /** * 该方法获取对应用户完成的编程题号 * @param questionId List<Integer> 题目id * @param username String 用户名 * @return Integer 题目集判断题总分 * @throws SQLException */ public List<Integer> getProgramCompleteNum(List<Integer> questionId, String username) throws SQLException; /** * 该方法获取用户答的题目的得分 * @param completeNum List<Integer> 已完成题目id * @return Integer 用户答的题目的总分 * @throws SQLException */ public Integer getProgramScore(List<Integer> completeNum) throws SQLException; }

自建数据库连接池#

按照传统的模式,每次执行 SQL 语句访问数据库时,都需要先建立一条连接,等 SQL 语句执行完毕后切断连接。但是连接的建立需要一定的资源开销,如果需要频繁地对数据库执行 SQL 语句,则这种模式会在连接的建立上造成巨大的开销,导致效率受到影响。此处如果有一个数据库连接池能预先建立多条连接,当需要建立连接时就分出一条连接支持操作,然后再会收回连接池继续利用,就可以优化效率。
此处我根据数据库连接池的原理设计了简易的数据库连接池,使用的是类队列的结构实现的,并且模仿了 C++ vector 在连接数不足时进行 2 倍扩容。

Copy Highlighter-hljs
package util; import java.util.ArrayList; import java.util.List; import java.sql.*; /** * ConnectPool 类为自建的可扩容的简易数据库连接池 * @author 林智凯 * @version 1.0 */ public class ConnectPool { private List<Connection> pool = new ArrayList<Connection>(); private Integer maxSize; /** * 数据库连接池的构造方法,预先分配5个Connection对象 */ public ConnectPool() throws SQLException { Integer num = 5; this.maxSize = num; for (int i = 0; i < num; i++) { Connection conn = MysqlConnect.connectDatabase(); this.pool.add(conn); } } /** * 向数据库连接池获取连接资源,返回一个 Connection 对象 * @return Connection 对象 */ public Connection getConnection() throws SQLException { //检查是否还有Connection对象可以分配 if(pool.size() == 0){ //Connection对象不够用,先扩容 for (int i = 0; i < this.maxSize; i++) { Connection conn = MysqlConnect.connectDatabase(); pool.add(conn); } //2倍扩容 this.maxSize *= 2; } //弹出第一个Connection对象返回 Connection conn = pool.remove(0); return conn; } /** * 回收 Connection 返回数据库连接池中。 * @param conn */ public void recoveryConnection(Connection conn){ pool.add(conn); } }

其中 MysqlConnect 类用于建立数据库连接的工具类,和 ConnectPool 类的关系用 UML 类图描述如下。

需要注意的是自建的 ConnectPool 类可能与 MySQL数据库的资源回收机制产生冲突,在特定的条件下连接会失效,因此建议使用连接池框架替换。

posted @   乌漆WhiteMoon  阅读(429)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示
CONTENTS