當我們嘗試用“Java 8 的方式”使用數據庫是,如何去解決性能上的問題呢?
通過與 ZeroTurnaround 合作,我們為你帶來了 Java Zone。你可以閱讀這裡的 8 個步驟的指南,來看看如何在編寫代碼時,利用跳過緩慢的應用程序重新部署的過程和實現應用程序分析來提高你的生產力吧!
Java 8 被發布的時候,人們開始讓所有的東西變成流,沒過多久他們就開始想象,如果可以將同樣的方式用在數據庫上,那將會有多棒。本質上數據庫就是由大型的數據塊以類似於表格的結構組織而成的。如 SQL 的 SELECT,WHERE,和 AS 語句向我們所表明的,這些結構對於過濾和映射操作很理想。(我們曾總結出)人們首先做的就是去向數據庫獲取到一個大型的數據集合,而後使用 Java8 中又新又酷的流技術來對這種數據進行處理。
有個問題立馬就出現了,這個問題就是將來自數據庫中的所有數據行轉移到數據庫中,其延時太長了。後果就是沒能有多少盈余留下來對內存中的數據進行處理。即使你可以使用 Java 8 中新的工具做一些真正令人驚訝的東西出來,但這種好處卻因為性能的消耗過甚而並不適用於數據庫應用程序。
當我開始想 Speedment 開源項目做貢獻是,很快就意識到用 Java 8 的方式利用數據庫的潛力,不過我們確實需要一個聰明的方式來處理性能問題。在本文中我會向你展示如何使用自定義的 Stream API 代理,在後台操作一個流,對於 SQL 查詢的結果進行優化,以解決這個問題。
假設在遠程數據庫服務器上你有一張用戶表,你想打印年齡大於 70 歲的用戶名字。 在 Java 8 中使用 Speedment 可能會是這樣:
final UserManager users = speedment.managerOf(User.class);
users.stream()
.filter(User.AGE.greaterThan(70))
.map(User.NAME.get())
.forEach(System.out::println);
看你這些代碼你不僅要先打一個冷顫,我的程序會從數據庫下載整個數據表,然後在客戶端做過濾嗎?如果我有 100,000,000 個用戶會發生什麼?網絡延遲足以殺死應用程序!哇噢,事實並不是這樣,就像我前面說過的。Speedment 在結束前會分析流。
讓我們來看看幕後發生了什麼。UserManager 中的方法 .stream() 會返回一個流接口的自定義實現,包含流的所有無數據一直到流關閉,元數據可以被終止的事件使用以優化流。當方法 .forEach 被調用時,管道看起來會是這樣:
終止活動(在這個例子中 ForEach 將會向後遍歷管道,看看它是否可以優化,首先它遇到從 User 到 String 的映射。Speedment 識別出它是一個 Getter 函數,User.NAME 字段是使用它來生成。Getter 可以解析到 SQL,所以終止活動切換到讀操作,因為 NAME 列和映射被移除。
接著是 .filter。filter 也被識別出是一個自定義操作,在這個例子中是一個謂詞。因為它是一個自定義實現,它可以包含 SQL 查詢中需要的所有元數據,所以可以安全地從流中移除並附加在寫操作)
此時終止活動繼續查找管道,它會發現流的源頭,一旦到達流的源頭,讀操作會解析到 SQL 並提交到 SQL 管理系統。最後 Stream<String> 會被最被的 .forEach 終止掉。上面的內容會生成確切的 SQL:
SELECT `name` FROM `User` WHERE `User`.`age` > 70;
Java 代碼不需要改變和特殊的操作!
這是一個簡單的例子,演示了流在執行前 Speedment 如何使用一個自定義實現使它簡化。歡迎你查看 the source code 尋找更好的辦法來優化這個技術。它真的幫助我們改善了系統性能,並在可以在 Java-8 的任何分布式環境下工作。
英文原文:Parsing Java 8 Streams Into SQL