如何用JDK8實作一個小型的關聯式資料庫系統
description
Transcript of 如何用JDK8實作一個小型的關聯式資料庫系統
如何用JDK8實作一個小型的關聯式資料庫系統
Kishida Naoki
2014-8-1 Taipei Java Developer Day
自己介紹
● きしだ なおき(Kishida Naoki)● 来了日本的福岡● 自由工作者
Blog/SNS
● Twitter– https://twitter.com/kis
● 部落格(きしだのはてな)– http://d.hatena.ne.jp/nowokay/
福岡
● 日本的西邊● 九州的北邊
● 九州=大概跟台灣一樣大
福岡
● 從福岡到東京跟從福岡到臺北(飛機兩個小時)
内容
● 自製資料庫● 實作
– Java 8 使用到的功能
– 其他程式庫
自製的資料庫● 主要用途是為了學習● 關聯式資料庫● 沒有資料形態● 單執行
– 多執行是複雜● 沒有網路● 記憶體上運作
– 不會存取到檔案系統
● github– https://github.com/kishida/sqlparser
資料庫的構造
● Parser● Planner● Optimizer(最佳化)
– Index
● Executor– Transaction
Parser
● 字串表示的 SQL 剖析
● 製作 AST 抽象語法樹
● 使用了 JParsec 來實作
Planner
● 抽象語法樹後 生邏輯執行計劃產● 邏輯執行計劃
– 詢的處理順序,用關聯式代數表示查● 關聯式代數
– 關聯式資料庫的基礎
Optimizer
● 將邏輯執行計劃製作物理執行計劃● 最佳化
– 節省不必要的處理
– 決定要使用的 index● 規則為基礎的演算法
– 用來設定好規則使用 index– 難支援複雜的 詢查
– 依照資料的分佈狀況,效率不好的狀況
→cost based 的演算法
物理執行計劃執行
● Transaction● MVCC
– MultiVersionConcurentControl
● 沒 commit 的資料不會被其他 transaction 看到
Java8的効能
● Stream● Optional
● 生新的 產 List
● 將List 中的資料處理後 生新的 產 List
– fields 的 List
– 所有 執行 值 eval 的方法
List<Value> result = new ArrayList<>();for(Field f : fields){ result.add(eval(f));}
● 生新的 產 List
● 用Stream● 這種類似處理非常多
● 使用 Stream 可以減輕很多負擔
List<Value> result = fields.stream() .map(f -> eval(f)) .collect(toList());
●判斷List
● List 的所有元素是否都符合條件的判斷
– conditions 的 List
– 元素在使用 hasOr
– 所有true 的話就 return
boolean result = true;for(Condition c : conditions){ if(!hasOr(c)) result = false;}if(result) return;
●判斷List
● 使用Stream– 一行就可以
– 可以在 if 直接使用
– 減少不必要的 result 變數
– 可以減少一些邏輯上出錯的問題
if(conditions.stream().allMatch(c -> hasOr(c))){ return;}
Optional
● 表示有沒有 的型別值
● Scala→Optiona、Haskell→Maybe● 通常使用 null
– 忘記做 null 檢 →查 NullPointerException– 從程式碼型別上根本就分辨不出來,變數有沒
有可能被指定成 null 的狀況
Optional
● ex:BufferedReader– readLine
● 沒有資料可以讀時會回傳 null● 不會知道他有可能回傳 null● 必須認真看文件
– 文件● 忘記寫● 常常 懶沒寫偷
– 忘記檢 查 null→NullPointerException
● 使用 Optional 就可以減少這類 NullPointerException 的狀況
Optional 的使用方法
● 建立 Optional– Optional.of(value)
– null 的時候, 會 生產 NullPointerException
– 參數不為 null 時才可以使用
● 不知道是不是 值 null– Optional.ofNullable(value)
● 表示沒有值
– Optional.empty()
從 Optional 取得值1
● get()
– 沒有值,丟出 NoSuchElementException– 請儘量不要這樣使用
● orElse(defaultValue)
– 沒有 時會回傳 值 defaultValue
從 Optional 取得值2
● orElseGet(() -> defualtValue)
– defaultValue 的計算可能會花一些時間
– 傳入一個型別為 Supplier
– 使用 lambda 式– 沒有 的時候才會執行值
– 只有在需要時才執行的動作● 延遲執行(Lazy Execution)
Optional 有 得時候才會想要執行某值些動作
● 判斷有沒有值
● isPresent()
– 有 →值 true
– 沒有值(empty)→false● 不是 Java 8 的風格
Optional<String> ostr = Optional.ofNullable(str);if(ostr.isPresent()){ System.out.println(ostr.get().length());}
Optional 有 得時候才會想要執行某值些動作
● ifPresent(Consumer c)● 只有在有 時會執行傳入的式值
● 參數的型別是Consumer
– 用 lambda 來寫
– 有 時才會執行值
Optional<String> ostr = Optional.ofNullable(str);ostr.ifPresent(s -> { System.out.println(s.length());});
轉換成其他值 值● map(Function<T, U>)
– 傳入回傳普通 的 值 lambda 式
– 回傳包著那個 得 值 Optional
– null的時候,變成empty
– 不用擔心 NullPointerException● flatMap(Function<T, Optional<U>)
– 傳入回傳Option的 lambda式
– 回傳剛剛的 OptionalOptional<String> ostr = Optional.ofNullable(str);ostr .map(String::length) .ifPresent(System.out::println);
當 符合條件才要處理值
● filter(Predicate<T>)
– 條件不符合會回傳 empty
Optional<String> ostr = Optional.ofNullable(str);ostr .map(String::length) .filter(len -> len < 5) .ifPresent(System.out::println);
map,filter,ifPresent
● 跟 map 還有 filter 之類的方法搭配處理時,非常有效果
● map・filter・ifPresent裡面
– 保證 不會是 值 null
– 不用擔心NullPointerException● 隔離有 null 的世界和沒有null 的世界● Optional要多打一些字 (^^
– 可以讓人寫的比較安心
– 請記得會出現 null 時就要利用 Optional
程式庫
● Lombok● JParsec
Lombok● http://projectlombok.org/● 可以把一些 Java 很繁雜的程式碼減少
● Setter/Getter
– 可以用 IDE 幫我們 生產
– 看起來一長串很煩
– 改也很麻煩
class Foo{ String message; public String getMessage(){ return message; } publilc void setMessage(String m){ this.message = m; }}
Lombok
● 清爽許多
class Foo{ @Setter @Getter String message;}
Lombok
● @NoArgsConstructor– 生預設建構子產
● @AllArgsConstructor– 成員變數都要設定的建構子
● @ToString– 生 產 toString
● @EqualsAndHashCode– 生 產 equals 和 hashcode
● 對應 IDE
JParsec
● http://jparsec.codehaus.org/● Parser Generator
– 産生抽象語法樹
● Haskell的Parsec移植● 用Java做 parser
– JavaCC和Antlr需要 Java 程式碼以外的語法定義檔
– 必須特別編譯
● 用 Java 來定義語法
– 不需要額外的檔案和編譯
JParsec的例
● delete的語法定義
public static Parser<ASTDelete> delete(){ return Parsers.sequence( terms.token("delete").next(terms.token("*").optional()) .next(terms.token("from")).next(identifier()), where().optional(), (id, w) -> new ASTDelete(id, Optional.ofNullable(w))); }
總結1
● 製作資料庫非常有幫助
– 資料庫的構造● MySQL、PostgreSQL、Oracle● 能大概知道他們到底在做什麼
– 能了解 SQL 的處理過程
● 可以寫出效率更好的 SQL
總結2
● Java8很方便
– 回不去Java7● Optional應該多加利用
– Java8中如果出現 nullpointerexception 就太失敗了
● Lombok– 可以從又臭又長麻煩的程式碼中解脫
● JParsec– 不知不覺的完成結構很大的語法定義,很有趣