用Java实现一个简单的DBMS(总结)
时间:2020/1/16
写这个DBMS(说DBMS夸张了,应该是一个控制台程序)的起因是数据库实践老师布置的一个大作业,先贴上GitHub地址: https://github.com/machi12/MyDatabase,如果大家觉得可以的话,希望点个star.
这篇博文主要会讲一下自己在实现这个DBMS时遇到的一些问题以及自己解决的思路.
一.实现功能
我写的这个DBMS实现了如下功能(主要的指令格式参照了MySQL的命令行指令):
1.show databases; //列出目前所有存在的数据库 2.create database 数据库名; //创建一个数据库 3.drop database 数据库名; //删除一个数据库 4.use 数据库名; //使用一个数据库 5.show tables; //列出当前数据库中存在的所有表 6.create table(列名 类型 约束, .......); //创建一个表 7.describe 表名; // 打印一个表的详细信息 8.insert into 表名 (列名,.....) values (值,......); //向表中插入数据 9.select * from 表名; //查询表中的所有数据 10.drop table 表名; //删除一个表 11.help; //帮助信息; 12.quit; //退出
下面是指令执行的截图:
1.
2.
3.
4.
5.
6.
二.项目配置
从GitHub仓库下载下来源码并解压后,需要在本地配置一下相关的信息. (我这里用的IDE是idea)
项目目录如下
要使这个项目可以在本地运行,需要更改SQLConstant.java中的相关代码
1 //数据库的根路径 2 private static final String path = "E:\\MyDatabase";
将上面的根目录改成本地的一个目录
1 //自定义的分隔符 2 private static final String separate = "~";
同时也可以自定义数据库中的分隔符,我这里使用的是"~".
更改完路径后这个代码就可以在本地运行了,创建的数据库都会在指定的路径下.
三.需要解决的问题
在这里我结合我在做这个系统的遇到的问题来说一下做一个简单的DBMS需要解决哪几个方面的问题:
1.对输入的语句进行标准化
在使用的过程中你要考虑到用户的输入可能不是百分百的符合标准的格式,你要确保在没有语法错误的情况下也能正确解析出用户输入的语句,比如大小写,多个空格以及换行符等.
2. 语句的解析
在进行完标准化后就可以进行语句的解析了,这部分主要是确定用户想要执行操作的大类,至于具体的操作,需要在大类中再细分.
3.语句的执行
在解析完语句后就会跳转到具体的类去执行相应的操作,对于操作问题,主要是创建删除文件以及对文件的读写等,当然,这里面也会有一些很细节的东西,比如你要自定义分隔符,这样在读写的时候才能和之前定义的字段一一对应,要不你不知道每个数据是从哪里分割的,当然还有其他问题,这个可能需要你写的时候慢慢想.
这部分只是给出操作时可能遇到的问题,主要想让大家在做之前想一下每部分怎么实现比较好,至于我的实现方法会在下面的部分具体给出.
四,问题的解决
1.对输入的语句进行标准化
对于这部分的实现,我做的并没有很细,只是把能想到的给做了,如去掉语句两端的空格,把多个空格转化为一个空格等,具体实现代码如下:
1 public static String sqlFromat(String input){ 2 String sql = ""; 3 //去掉最后的;和空格 4 //sql = input.replaceAll(";", ""); 5 //去掉字符串前后两端的空格 6 sql = input.trim(); 7 //将字符串都转化为小写 8 String string = sql.toLowerCase(); 9 //通过正则表达式将多个空格转换为一个空格 10 String str = string.replaceAll("\\s{2,}", " "); 11 //去掉;前的空格 12 String s = str.replaceFirst("( ;)$", ";"); 13 //System.out.println(s); 14 return s; 15 }
我对于所有的语句默认必须以;结尾,在项目的Input类中我会通过endsWith方法判断输入语句的最后一个字符是不是";". 如果是,则结束输入并将输入的语句交给SqlAnalysis类进行解析.
2.语句解析
将输入的语句传到语句解析方法中,根据正则表达式匹配语句中的第一个单词来转到相应的语句处理类中.这里的解析只是一个大类上的解析,根据输入语句的第一个单词进行处理,函数如下:
1 package sdnu.machi; 2 3 import java.util.regex.Matcher; 4 import java.util.regex.Pattern; 5 6 /** 7 * @ Description : 实现一个sql解析器,目前支持create, show, use, quit 8 * @ Author : 马驰 9 * @ CreateDate : 2019/12/26 17:03 10 */ 11 public class SqlAnalysis { 12 13 //private static String[] str; 14 //private static final String path = "E:\\MyDatabase"; 15 //下面是目前支持的sql语句类型 16 private static final String create = "create"; 17 private static final String help = "help"; 18 private static final String show = "show"; 19 private static final String use = "use"; 20 private static final String quit = "quit"; 21 private static final String describe = "describe"; 22 private static final String insert = "insert"; 23 private static final String select = "select"; 24 private static final String drop = "drop"; 25 26 27 public static void analysis(String sql){ 28 //str = sql.split(" "); 29 String start = ""; 30 //正则表达式的匹配规则 31 String regex = "^[a-z]+"; 32 Pattern pattern = Pattern.compile(regex); 33 Matcher matcher = pattern.matcher(sql); 34 //获取匹配值 35 while(matcher.find()){ 36 start = matcher.group(); 37 } 38 39 //根据第一个单词判断该语句的作用 40 switch (start){ 41 case create: 42 Create.createSql(sql); 43 break; 44 case help: 45 Help.help(); 46 break; 47 case show: 48 Show.showSql(sql); 49 break; 50 case use: 51 Use.useSql(sql); 52 break; 53 case quit: 54 Quit.quitSql(); 55 break; 56 case describe: 57 Describe.describeSql(sql); 58 break; 59 case insert: 60 Insert.insertSql(sql); 61 break; 62 case select: 63 Select.selectSql(sql); 64 break; 65 case drop: 66 Drop.dropSql(sql); 67 break; 68 default: 69 System.out.println("输入的命令无法识别,可以输入help查看目前支持的sql语句"); 70 Input.get(); 71 break; 72 } 73 //System.out.println(start); 74 } 75 76 77 }
3.语句的执行
语句的执行这部分主要有两个方面的任务:
一是对从第二步解析完的指令进行进一步的细分,就以create指令来说,当你在第二步识别出这是一个create指令后,你还要接着识别这是一个create table还是create database指令,因为这两种指令完成的操作是不一样的.
二是对细分后的指令进行执行操作,这里涉及到操作就比较多,一是映射问题,我这里把一个数据库映射成一个文件夹,把一个数据表映射成一个txt文件(如果你使用xlxs格式或者csv格式的话会更加容易,因为这样你就不需要考虑分隔符的问题,这些文件格式有自己定义的分割符). 二是控制信息(列名,类型,主外键等)和数据信息存放位置的问题,你是要单独为每一个表创建一个存放控制信息文件还是在一个文件中同时存放控制信息和数据信息,我这里采用的是第二种方式,我把一个txt文件的前三行用来存放控制信息(第一行是列名,第二是数据类型,第三行其余信息),之后的位置用来存放数据信息. 三是转义的问题,如果数据中含有你的分隔符要怎么存放,我这里是如果含有,则在分隔符前面再加一个分隔符,取的时候去掉多余的.还有其他可能存在的问题,这里可能记不太清了(原谅我,考试周复习的有点记不得了......)
对于每个操作我都对用一个java类,例如create操作我写了一个create类,由于代码较多,我就不贴出来了,大家可以在GitHub上下载下来看.
五.最后
在写这个项目之前自己也查过很多资料,在查的过程中不乏有劝退的,理由无非是网上这方面的开源项目已经很多了,没有必要去花时间造轮子了.做完后就说一下自己的想法吧,如果你觉得你不确定能不能做出来的情况下,最好去做一下,感觉做完之后还是蛮有提高的,而且对于自己的信心提升也挺大,如果你感觉你的能力做这样一个东西太简单了,那就没有必要了,花时间去看一些最新的框架比这个提升会更大.
最后,新的一年和大家在这里共勉.希望在2020年考研顺利,继续开心的撸代码.