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


    实现一下题目管理模块

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

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

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

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

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

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

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

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

    1. create database if not exists NowOJ;
    2. use NowoJ;
    3. drop table if exists TitleList;
    4. create table TitleList(
    5. TitleID int primary key auto_increment,
    6. TitleData varchar(40),
    7. TitleLevel varchar(40),
    8. Description varchar(10000),
    9. PreJavaCode varchar(4096),
    10. TestCode varchar(4096)
    11. );
    1. package MYSQL;
    2. import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
    3. import javax.sql.DataSource;
    4. import java.sql.Connection;
    5. import java.sql.PreparedStatement;
    6. import java.sql.ResultSet;
    7. import java.sql.SQLException;
    8. public class ConnectionMysql {
    9. private static final String url="jdbc:mysql://127.0.0.1:3306/NowOJ?characterEncoding=utf-8&userSSL=true";
    10. private static final String user="root";
    11. private static final String password="12503487";
    12. private static volatile DataSource dataSource=null;
    13. private static DataSource GetDataSource()
    14. {
    15. if(dataSource==null){
    16. synchronized (Object.class){
    17. if(dataSource==null)
    18. {
    19. dataSource=new MysqlDataSource();
    20. ((MysqlDataSource)dataSource).setURL(url);
    21. ((MysqlDataSource)dataSource).setPassword(password);
    22. ((MysqlDataSource)dataSource).setUser(user);
    23. }
    24. }
    25. }
    26. return dataSource;
    27. }
    28. public Connection GetConnection() throws SQLException {
    29. return GetDataSource().getConnection();
    30. }
    31. public static void close(Connection connection, PreparedStatement preparedStatement, ResultSet resultSet) throws SQLException {
    32. if(resultSet!=null)
    33. {
    34. resultSet.close();
    35. }
    36. if(preparedStatement!=null)
    37. {
    38. preparedStatement.close();
    39. }
    40. if(connection!=null)
    41. {
    42. connection.close();
    43. }
    44. }
    45. }

    创建一个实体类对象:

    实体类:一个实体类对象就对应着表中的一条记录,一个实体类的一个属性对应着一张表的一条记录,并生成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里面;

    1. package MYSQL;
    2. import com.mysql.jdbc.MySQLConnection;
    3. import java.sql.Connection;
    4. import java.sql.PreparedStatement;
    5. import java.sql.ResultSet;
    6. import java.sql.SQLException;
    7. import java.util.ArrayList;
    8. import java.util.List;
    9. public class OperateTitle {
    10. public void insert(OJTitle ojTitle) throws SQLException {
    11. //1与数据库建立连接
    12. Connection connection=ConnectionMysql.GetConnection();
    13. //2构建SQL语句
    14. String SQL="insert into TitleList values(null,?,?,?,?,?)";
    15. PreparedStatement statement= connection.prepareStatement(SQL);
    16. statement.setString(1,ojTitle.getTitleData());
    17. statement.setString(2,ojTitle.getTitleLevel());
    18. statement.setString(3,ojTitle.getDescription());
    19. statement.setString(4,ojTitle.getPreJavaCode());
    20. statement.setString(5,ojTitle.getTestCode());
    21. //3进行执行SQL
    22. int len=statement.executeUpdate();
    23. if(len==1)
    24. {
    25. System.out.println("一道题插入成功");
    26. }else{
    27. System.out.println("一道题插入失败");
    28. }
    29. ConnectionMysql.close(connection,statement,null);
    30. }
    31. public void delete(int TitleID) throws SQLException {
    32. Connection connection= ConnectionMysql.GetConnection();
    33. String SQL="delete from TitleList where TitleID=?";
    34. PreparedStatement statement= connection.prepareStatement(SQL);
    35. statement.setInt(1,TitleID);
    36. int len=statement.executeUpdate();
    37. if(len==1)
    38. {
    39. System.out.println("删除成功");
    40. }else{
    41. System.out.println("删除失败");
    42. }
    43. ConnectionMysql.close(connection,statement,null);
    44. }
    45. public List selectAll() throws SQLException {
    46. //1与数据库建立连接
    47. List list=new ArrayList<>();
    48. Connection connection=ConnectionMysql.GetConnection();
    49. //2进行拼装SQL语句
    50. String SQL="select * from TitleList";
    51. PreparedStatement statement=connection.prepareStatement(SQL);
    52. ResultSet resultSet= statement.executeQuery();
    53. while(resultSet.next())
    54. {
    55. OJTitle ojTitle=new OJTitle();
    56. ojTitle.setTitleID(resultSet.getInt("TitleID"));
    57. ojTitle.setTitleData(resultSet.getString("TitleData"));
    58. ojTitle.setTitleLevel(resultSet.getString("TitleLevel"));
    59. ojTitle.setDescription(resultSet.getString("PreJavaCode"));
    60. ojTitle.setTestCode(resultSet.getString("TestCode"));
    61. list.add(ojTitle);
    62. }
    63. ConnectionMysql.close(connection,statement,null);
    64. System.out.println("查询所有成功");
    65. return list;
    66. }
    67. public OJTitle selectOne(int TitleID) throws SQLException {
    68. 由于题目列表是自增主键,我们查询到的结果一定只有一条数据
    69. Connection connection=ConnectionMysql.GetConnection();
    70. String SQL="select * from titlelist where TitleID=?";
    71. PreparedStatement statement=connection.prepareStatement(SQL);
    72. statement.setInt(1,TitleID);
    73. ResultSet resultSet= statement.executeQuery();
    74. System.out.println(resultSet);
    75. OJTitle ojTitle=new OJTitle();
    76. while(resultSet.next()) {
    77. ojTitle.setTitleID(resultSet.getInt("TitleID"));
    78. ojTitle.setTitleData(resultSet.getString("TitleData"));
    79. ojTitle.setTitleLevel(resultSet.getString("TitleLevel"));
    80. ojTitle.setDescription(resultSet.getString("PreJavaCode"));
    81. ojTitle.setTestCode(resultSet.getString("TestCode"));
    82. }
    83. ConnectionMysql.close(connection,statement,null);
    84. System.out.println("查询一个成功");
    85. return ojTitle;
    86. }
    87. public static void main(String[] args) throws SQLException {
    88. OJTitle ojTitle=new OJTitle();
    89. OperateTitle operateTitle=new OperateTitle();
    90. // ojTitle.setTitleData("A");
    91. // ojTitle.setTitleLevel("OK");
    92. // ojTitle.setDescription("please write");
    93. // ojTitle.setTestCode("psvm");
    94. // ojTitle.setTestCode("HH");
    95. // operateTitle.insert(ojTitle);
    96. // List list= operateTitle.selectAll();
    97. // OJTitle ojTitle1= operateTitle.selectOne(1);
    98. // System.out.println(list);
    99. // System.out.println(ojTitle1);
    100. // operateTitle.delete(1);
    101. }
    102. }

    注意: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字段

    1. 用户提交的代码:
    2. package MYSQL;
    3. public class Solution {
    4. public int[] twoSum(int nums[],int target)
    5. {
    6. //这里面存放用户自己写的代码
    7. }
    8. }
    9. 我们所写的测试用例的方法:
    10. public static void main(String[] args) {
    11. int[] nums={2,7,11,15};
    12. int target=9;
    13. Solution solution=new Solution();
    14. int[] arr1= solution.twoSum(nums,target);
    15. if(arr1.length==2&&arr1[0]==0&&arr1[1]==1)
    16. {
    17. System.out.println("Test OK");
    18. }else{
    19. System.out.println("Test failed");
    20. }
    21. int[] nums1={3,3,6};
    22. target=6;
    23. int[] arr2= solution.twoSum(nums1,target);
    24. if(arr2.length==2&&arr2[0]==1&&arr2[1]==2)
    25. {
    26. System.out.println("Test OK");
    27. }else{
    28. System.out.println("Test failed");
    29. }
    30. }

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

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

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

  • 相关阅读:
    腾讯云短信服务实现 Java 发送手机验证码(SpringBoot+Redis 实现)
    k8s-16 statefulse控制器
    软件设计思想
    一篇文章带你解1+X Web 前端开发考核考纲(详细介绍)(涵盖初级、中级、高级)
    大公司为什么禁止SpringBoot项目使用Tomcat?
    CSS_关系选择器
    NX二次开发-NX+VS写代码设断点调试技巧
    使用spring的计时器StopWatch,更简洁方便(附源码)
    list,dict使用方法
    【C++航海王:追寻罗杰的编程之路】string类
  • 原文地址:https://blog.csdn.net/weixin_61518137/article/details/125996062