zoukankan      html  css  js  c++  java
  • Java 课程设计:LWZ

    数据库设计

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

    用户部分

    users 表

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

    题目部分

    choice 表

    存储选择题题目的数据。

    judgment 表

    存储判断题题目的数据。

    编程题存储

    program 表

    存储编程题题目的数据。

    testpoint 表

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

    subjective

    存储主观题题目的数据。

    collections 表

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

    作答记录部分

    codes 表

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

    answer 表

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

    score 表

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

    班级管理部分

    classes 表

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

    task 表

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

    站内短信部分

    emails 表

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

    数据库读写

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

    CodeRepositoryDAO 接口

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

    /**
    * 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 类图如下。

    /**
    * 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 类图如下。

    /**
    * 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 倍扩容。

    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数据库的资源回收机制产生冲突,在特定的条件下连接会失效,因此建议使用连接池框架替换。

  • 相关阅读:
    Mysql 索引原理《一》索引原理与慢查询2
    Mysql 索引原理《一》索引原理与慢查询1
    Mysql内置功能《六》流程控制
    Mysql内置功能《五》 函数
    Mysql内置功能《四》存储过程
    Mysql pymysql模块
    HDU2020 绝对值排序
    HDU2019 数列有序
    HDU2018 母牛的故事
    HDU2016 数据的交换输出
  • 原文地址:https://www.cnblogs.com/linfangnan/p/14342754.html
Copyright © 2011-2022 走看看