在线OJ项目(2)---封装设计数据库

实现一下题目管理模块

1)创建题目表,我们要进行设计一下里面的字段和属性:

1.1)设置题目的序号:作为题目表的自增主键

1.2)题目的标题(两数之和)

1.3)题目的难度(简单,中等,困难)

1.4)题目的具体要求描述,也叫做题干,不同的题目,题目描述是不相同的

1.5)题目的给定的代码模板,给用户展示的初始代码用户要在这个代码模板的基础上面做题

1.6)题目的测试用例(不会进行展示给前端);

我们的这个datasource是单例模式的,只要有一个数据库,那么它就是单例模式的

create database if not exists NowOJ;
use NowoJ;
drop table  if exists TitleList;
create table TitleList(
TitleID int primary key auto_increment,
TitleData varchar(40),
TitleLevel varchar(40),
Description varchar(10000),
PreJavaCode varchar(4096),
TestCode varchar(4096)
);

package MYSQL;
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class ConnectionMysql {
    private static final String url="jdbc:mysql://127.0.0.1:3306/NowOJ?characterEncoding=utf-8&userSSL=true";
    private static final String user="root";
    private static final String password="12503487";
   private static volatile DataSource dataSource=null;
  private static DataSource GetDataSource()
  {
      if(dataSource==null){
          synchronized (Object.class){
              if(dataSource==null)
              {
                  dataSource=new MysqlDataSource();
                  ((MysqlDataSource)dataSource).setURL(url);
                  ((MysqlDataSource)dataSource).setPassword(password);
                  ((MysqlDataSource)dataSource).setUser(user);
              }
          }
      }
      return dataSource;
  }
  public Connection GetConnection() throws SQLException {
      return GetDataSource().getConnection();
  }
  public static void close(Connection connection, PreparedStatement preparedStatement, ResultSet resultSet) throws SQLException {
      if(resultSet!=null)
      {
          resultSet.close();
      }
      if(preparedStatement!=null)
      {
          preparedStatement.close();
      }
      if(connection!=null)
      {
          connection.close();
      }
  }
}

创建一个实体类对象:

实体类:一个实体类对象就对应着表中的一条记录,一个实体类的一个属性对应着一张表的一条记录,并生成Getter和Setter,ToString方法,我们的Java代码的字段是和数据库中的表的字段是相同的;

封装题目表操作:

我们在这里面要实现的功能是:

1)新增题目(参数直接给定一个题目)

2)删除题目(根据题目ID来进行删除)

3)进行查询题目列表,进行给题目列表页来进行服务的,在我们的题目列表页里面,我们只需要进行获取三条数据即可,题目ID,题目名字还有题目的难易程度;

4)查询题目详情,根据题目ID来进行查询,所有有关于题目的信息都要进行查询;

在这里面,不同的用户的操作权限是不一样的,我们的管理员是负责进行删除和新增题目,而我们的普通用户只进行负责查

我们在这里面一定要注意一个事情:

1)我们在数据库里面进行查找题目列表操作,主要是给题目列表页来进行使用的,我们进行查找的时候,直接用select *.....,这种查询方法就会太粗暴了,数据库往往是最重要的一个模块,同时往往也是最脆弱的模块,数据库里面会存放很多很多数据,这些数据都是存放在磁盘上面的,当我们进行一些大规模操作的时候,如果进行select *操作,如果说表比较大,那么有可能直接把数据库服务器给卡死了,况且网络带宽就被吃满了,客户端和服务器是通过网络来实现数据交互的,磁盘IO基本被吃满,磁盘上面查数据很麻烦

2)如果说我们要是有大量的数据的话,我们可以使用分页查询来进行查找,我们是可以根据前端传递过来的页数来进行分页查询的,比如说我们一页有50条数据,假设我们现在用户点击的页码是三,那么此时的offset就应该是100

(页数*一页中的条数)-1;

我们这是就可以根据前端传递过来的页码,根据页码进行算一下,根据sql limit offset语句,要算出来offset是多少

1--->0-49

2--->50-99

3--->100-149

3)我们在与数据库建立连接的时候,最终是要进行关闭资源的,那么我们可不可以把关闭语句写道try语句里面呢?一旦我们的try里面的语句出现了问题,发生了异常,那么我们的程序就很有可能直接跳转到catch语句里面了,就可能无法执行到关闭语句了,所以我们的关闭操作一定要放到finally里面;

package MYSQL;

import com.mysql.jdbc.MySQLConnection;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

public class OperateTitle {
   public void insert(OJTitle ojTitle) throws SQLException {
       //1与数据库建立连接
       Connection connection=ConnectionMysql.GetConnection();
       //2构建SQL语句
       String SQL="insert into TitleList values(null,?,?,?,?,?)";
       PreparedStatement statement= connection.prepareStatement(SQL);
       statement.setString(1,ojTitle.getTitleData());
       statement.setString(2,ojTitle.getTitleLevel());
       statement.setString(3,ojTitle.getDescription());
       statement.setString(4,ojTitle.getPreJavaCode());
       statement.setString(5,ojTitle.getTestCode());
       //3进行执行SQL
       int len=statement.executeUpdate();
       if(len==1)
       {
           System.out.println("一道题插入成功");
       }else{
           System.out.println("一道题插入失败");
       }
       ConnectionMysql.close(connection,statement,null);
   }
   public void delete(int TitleID) throws SQLException {
       Connection connection= ConnectionMysql.GetConnection();
       String SQL="delete from TitleList where TitleID=?";
       PreparedStatement statement= connection.prepareStatement(SQL);
       statement.setInt(1,TitleID);
       int len=statement.executeUpdate();
       if(len==1)
       {
           System.out.println("删除成功");
       }else{
           System.out.println("删除失败");
       }
       ConnectionMysql.close(connection,statement,null);
   }
   public List<OJTitle> selectAll() throws SQLException {
       //1与数据库建立连接
       List<OJTitle> list=new ArrayList<>();
       Connection connection=ConnectionMysql.GetConnection();
       //2进行拼装SQL语句
       String SQL="select * from TitleList";
       PreparedStatement statement=connection.prepareStatement(SQL);
       ResultSet resultSet= statement.executeQuery();
       while(resultSet.next())
       {
           OJTitle ojTitle=new OJTitle();
           ojTitle.setTitleID(resultSet.getInt("TitleID"));
           ojTitle.setTitleData(resultSet.getString("TitleData"));
           ojTitle.setTitleLevel(resultSet.getString("TitleLevel"));
           ojTitle.setDescription(resultSet.getString("PreJavaCode"));
           ojTitle.setTestCode(resultSet.getString("TestCode"));
           list.add(ojTitle);
       }
       ConnectionMysql.close(connection,statement,null);
       System.out.println("查询所有成功");
       return list;
   }
   public OJTitle selectOne(int TitleID) throws SQLException {
由于题目列表是自增主键,我们查询到的结果一定只有一条数据
       Connection connection=ConnectionMysql.GetConnection();
       String SQL="select * from titlelist where TitleID=?";
       PreparedStatement statement=connection.prepareStatement(SQL);
       statement.setInt(1,TitleID);
       ResultSet resultSet= statement.executeQuery();
       System.out.println(resultSet);
       OJTitle ojTitle=new OJTitle();
       while(resultSet.next()) {
           ojTitle.setTitleID(resultSet.getInt("TitleID"));
           ojTitle.setTitleData(resultSet.getString("TitleData"));
           ojTitle.setTitleLevel(resultSet.getString("TitleLevel"));
           ojTitle.setDescription(resultSet.getString("PreJavaCode"));
           ojTitle.setTestCode(resultSet.getString("TestCode"));
       }
       ConnectionMysql.close(connection,statement,null);
       System.out.println("查询一个成功");
      return ojTitle;
   }

    public static void main(String[] args) throws SQLException {
        OJTitle ojTitle=new OJTitle();
        OperateTitle operateTitle=new OperateTitle();
//        ojTitle.setTitleData("A");
//        ojTitle.setTitleLevel("OK");
//        ojTitle.setDescription("please write");
//        ojTitle.setTestCode("psvm");
//        ojTitle.setTestCode("HH");
//        operateTitle.insert(ojTitle);
//        List<OJTitle> list= operateTitle.selectAll();
 //       OJTitle ojTitle1= operateTitle.selectOne(1);
  //      System.out.println(list);
 //       System.out.println(ojTitle1);
 //       operateTitle.delete(1);
    }

}

注意:MYSQL在进行指定字段进行查询的时候,不要写成:

select (username,password) from user,不要加括号

为了验证上述我们所写的数据库模块是否有问题,我们进行设计测试用例并进行验证

1)其实当我们在进行构造数据库数据的时候,其他字段都好办,但是测试用例代码不好处理,因为测试用例代码我们无法从leetcode拷贝过来的

2)我们用户提交的代码是一个类,里面包含了方法,我们进行设计测试用例的时候,就要创建main方法,调用我们所的写的前端在线提交的OJ代码,然后进行执行

3)其实我们在设计测试用例的时候,就是一个main方法,但是在这个main方法里面,我们会创建Solution的实例,并调用里面的核心方法(twoSum)(做题人自己写的方法代码),当调用核心方法(里面的逻辑是我们是我们自己写的)的时候,传入不同的参数,并针对返回结果做不同的判定,如果说返回结果符合预期,那么就打印”TestOK“,如果不符合预期,那么就进行打印Test failed,还打印出出错的详情

3)在我们的服务器里面,我们会收到Solution类的完整实现代码,此时用户提交的代码没有main方法,我们在从数据库中查找到对应的测试用例代码,将两个代码进行字符串拼接,此时这个Solution就有main方法了,我们就可以单独的进行编译和运行了,此时的这个字符串就是我们前面写的Question类中的字符串,就是preJavaCode字段

用户提交的代码:
package MYSQL;
public class Solution {
    public int[] twoSum(int nums[],int target)
    {
        //这里面存放用户自己写的代码
       
    }
}
我们所写的测试用例的方法:
    public static void main(String[] args) {
        int[] nums={2,7,11,15};
        int target=9;
        Solution solution=new Solution();
        int[] arr1= solution.twoSum(nums,target);
        if(arr1.length==2&&arr1[0]==0&&arr1[1]==1)
        {
            System.out.println("Test OK");
        }else{
            System.out.println("Test failed");
        }
        int[] nums1={3,3,6};
        target=6;
        int[] arr2= solution.twoSum(nums1,target);
        if(arr2.length==2&&arr2[0]==1&&arr2[1]==2)
        {
            System.out.println("Test OK");
        }else{
            System.out.println("Test failed");
        }
    }

我们要将上述的测试代码和用户进行提交的代码进行拼接,然后执行

此时进行测试的代码只是将最核心的流程跑了一遍,而没有进行考虑更多的细节,这就被称之为冒烟测试,我们只测试了这几种方法(增删查改);这几个方法对了,就说明代码核心流程功能没有太大问题,这就类似于以前工程中用的板子,板子焊接好之后,只要他不冒烟,先别说他焊的对不对,但是从大致流程上面看是没有问题的;

但是从另一个角度来说,我们此时有针对每一个方法进行测试,这又被称为单元测试,发现问题越早问题就好解决;

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值