時間: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年考研順利,繼續開心的擼代碼.