Java 8 Friday:Java 8将彻底改变数据库访问
在Data Geekery ,我們喜歡Java。 而且,由于我們真的很喜歡jOOQ的流暢的API和查詢DSL ,我們對Java 8將為我們的生態系統帶來什么感到非常興奮。 對于Java 8系列 ,我們很榮幸主持Iu Ming-Yee Iu博士發表的非常相關的嘉賓帖子。
Iu Ming-Yee博士在EPFL獲得了Java數據庫查詢博士學位。 他創建了開源項目Jinq,以演示一些支持Java中數據庫查詢的新技術。
我們的社論注釋:
自從Erik Meijer將LINQ引入.NET生態系統以來,我們Java的人們一直在想是否可以擁有相同的東西。 之前,我們已經寫過幾次有關此主題的博客:
- Java 8仍然需要LINQ嗎? 還是比LINQ更好?
- LINQ和Java
- Java Streams Preview與.Net LINQ
- Java是否將LINQ添加到JSR-341中的EL 3.0?
- 什么時候用Java編寫LINQ?
盡管Java生態系統中的大多數LINQesque API都以內部特定于域的語言(如jOOQ)運行 ,但有些人卻嘗試在字節碼級別上解決集成問題,例如JaQu 。
JINQ通過Iu Ming-Yee Iu博士所說的符號執行來形式化運行時字節碼轉換。 我們發現這一點非常有趣,以至于我們不知道是否應該開始構建JINQ到jOOQ的JINQ提供程序,在該提供程序中Java 8 Streams API的表達能力可以與我們強大的SQL標準化和轉換功能結合起來嗎?
說服自己:
Java 8 Goodie:Java 8將徹底改變數據庫訪問
Java 8終于來了! 經過多年的等待,Java程序員最終將獲得對Java函數式編程的支持。 功能編程支持有助于簡化現有代碼,同時為Java語言提供強大的新功能。 這些新功能將干擾的一個方面是程序員如何使用Java處理數據庫。 功能編程支持為更簡單但功能更強大的數據庫API開辟了令人興奮的新可能性。 Java 8將提供新的方法來訪問與其他編程語言(例如C#的LINQ)競爭的數據庫。
處理數據的功能方式
Java 8不僅為Java語言增加了功能支持,而且還通過使用數據的新功能方式擴展了Java集合類。 傳統上,使用Java處理大量數據需要大量循環和迭代器。
例如,假設您有一個Customer對象的集合:
Collection<Customer> customers;如果您只對來自比利時的客戶感興趣,則必須遍歷所有客戶并保存所需的客戶。
Collection<Customer> belgians = new ArrayList<>(); for (Customer c : customers) {if (c.getCountry().equals("Belgium"))belgians.add(c); }這需要五行代碼。 它的抽象性也很差。 如果您有1000萬客戶,并且希望通過使用兩個線程并行過濾代碼來加快代碼處理速度,會發生什么情況? 您將不得不重寫所有內容以使用期貨和許多冗長的多線程代碼。
使用Java 8,您可以在一行中編寫相同的代碼。 借助對函數式編程的支持,Java 8使您可以編寫函數,說出您對哪些客戶感興趣(來自比利時的客戶),然后使用該函數過濾集合。 Java 8有一個新的Streams API,可讓您執行此操作。
customers.stream().filter(c -> c.getCountry().equals("Belgium") );Java 8版本的代碼不僅更短,而且代碼也更易于理解。 幾乎沒有樣板。 該代碼調用方法filter() ,因此很明顯,該代碼用于過濾客戶。 您不必花時間嘗試在循環中破譯代碼,以了解其對數據的處理方式。
如果要并行運行代碼會發生什么? 您只需要使用其他類型的流。
customers.parallelStream().filter(c -> c.getCountry().equals("Belgium") );更令人興奮的是,這種功能性的代碼樣式也適用于數據庫!
使用數據庫的功能方式
傳統上,程序員需要使用特殊的數據庫查詢語言來訪問數據庫中的數據。 例如,下面是一些JDBC代碼,用于查找比利時的所有客戶:
PreparedStatement s = con.prepareStatement("SELECT * "+ "FROM Customer C "+ "WHERE C.Country = ? "); s.setString(1, "Belgium"); ResultSet rs = s.executeQuery();許多代碼都是字符串形式的,編譯器無法檢查字符串,并且由于草率的編碼可能導致安全問題。 還有很多樣板代碼,使得編寫數據庫訪問代碼非常繁瑣。 jOOQ之類的工具通過提供可以使用特殊Java庫編寫的數據庫查詢語言來解決錯誤檢查和安全性問題。 或者,您可以使用對象關系映射器之類的工具為常見的訪問模式隱藏許多無聊的數據庫代碼,但是如果您需要編寫非平凡的數據庫查詢,則仍然需要再次使用特殊的數據庫查詢語言。
使用Java 8,可以使用與Streams API相同的功能樣式編寫數據庫查詢。 例如, Jinq是一個開源項目,探討了未來的數據庫API如何利用功能編程。 這是使用Jinq編寫的數據庫查詢:
customers.where(c -> c.getCountry().equals("Belgium") );該代碼與使用Streams API的代碼幾乎相同。 實際上,Jinq的未來版本將使您可以直接使用Streams API編寫查詢。 運行代碼時,Jinq會自動將代碼轉換為數據庫查詢,就像前面顯示的JDBC查詢一樣。
因此,無需學習新的數據庫查詢語言,就可以編寫高效的數據庫查詢。 您可以使用與Java集合相同的代碼樣式。 您也不需要特殊的Java編譯器或虛擬機。 所有這些代碼都使用普通的Java 8 JDK進行編譯和運行。 如果您的代碼中有錯誤,則編譯器會發現它們并將其報告給您,就像普通的Java代碼一樣。
Jinq支持與SQL92一樣復雜的查詢。 支持選擇,投影,聯接和子查詢。 將Java代碼轉換為數據庫查詢的算法在接受和轉換何種代碼方面也非常靈活。 例如,盡管Jinq很復雜,但將下面的代碼轉換為數據庫查詢沒有問題。
customers.where( c -> c.getCountry().equals("Belgium") ).where( c -> {if (c.getSalary() < 100000)return c.getSalary() < c.getDebt();elsereturn c.getSalary() < 2 * c.getDebt();} );如您所見,Java 8中的功能編程支持非常適合編寫數據庫查詢。 查詢是緊湊的,并且支持復雜的查詢。
內部工作
但是,這一切如何運作? 普通的Java編譯器如何將Java代碼轉換為數據庫查詢? Java 8有什么特別之處可以實現這一點?
支持這些新的功能樣式數據庫API的關鍵是一種字節碼分析,稱為符號執行。 盡管您的代碼是由普通的Java編譯器編譯并在普通的Java虛擬機中運行的,但是Jinq能夠在運行時分析已編譯的Java代碼并從中構造數據庫查詢。 在分析小功能時,符號執行效果最好,這在使用Java 8 Streams API時很常見。
理解此符號執行的工作原理的最簡單方法是一個示例。 讓我們研究一下Jinq如何將以下查詢轉換為SQL查詢語言:
customers.where( c -> c.getCountry().equals("Belgium") )最初, customers變量是一個代表此數據庫查詢的集合
SELECT *FROM Customers C然后,調用where()方法,并將一個函數傳遞給它。 在這種where()方法中,Jinq打開函數的.class文件,并獲取編譯后的字節碼供函數分析。 在此示例中,我們不使用實際的字節碼,而只是使用一些簡單的指令來表示函數的字節碼:
在這里,我們假設該函數已被Java編譯器編譯為四個指令。 這是Jinq在調用where()方法時看到的。 Jinq如何理解此代碼?
Jinq通過執行代碼來分析代碼。 Jinq不會直接運行代碼。 它“抽象地”運行代碼。 Jinq在執行代碼時不使用實變量和實值,而是使用符號來表示所有值。 這就是為什么將分析稱為符號執行的原因 。
Jinq執行每條指令,并跟蹤程序狀態中所有副作用或代碼更改的所有事物。 下圖顯示了Jinq使用符號執行來執行四行代碼時發現的所有副作用。
符號執行示例
在該圖中,您可以看到在執行第一條指令之后,Jinq如何發現兩個副作用:變量d發生了變化,并且調用了Customer.getCountry()方法。 在執行符號時,不會給變量d像“美國”或“丹麥”那樣的真實值。 它被分配了c.getCountry()的符號值。
在象征性地執行了所有指令之后,Jinq修剪了副作用。 由于變量d和e是局部變量,因此在函數退出后對它們的任何更改都將被丟棄,因此可以忽略那些副作用。 Jinq還知道, Customer.getCountry()和String.equals()不會修改任何變量或顯示任何輸出,因此也可以忽略這些方法調用。 由此,Jinq可以得出結論,執行該函數只會產生一種效果:它返回c.getCountry().equals("Belgium") 。
一旦Jinq理解了where()方法中傳遞給它的函數的功能后,它便可以將此知識與customers集合基礎的數據庫查詢合并,以創建新的數據庫查詢。
生成數據庫查詢
這就是Jinq從您的代碼生成數據庫查詢的方式。 使用符號執行意味著這種方法對于不同Java編譯器輸出的不同代碼模式非常健壯。 如果Jinq遇到帶有副作用的代碼,而這些副作用是使用數據庫查詢無法模擬的,那么Jinq將保持您的代碼不變。 由于所有內容都是使用常規Java代碼編寫的,因此Jinq可以直接直接運行該代碼,您的代碼將產生預期的結果。
這個簡單的翻譯示例應該使您了解查詢翻譯的工作方式。 您應該對這些算法可以從您的代碼正確生成數據庫查詢充滿信心。
美好的未來
我希望我對Java 8如何啟用Java中使用數據庫的新方式有所幫助。 Java 8中的功能性編程支持使您可以類似于編寫用于Java集合的代碼的方式來編寫數據庫代碼。 希望現有數據庫API不久將得到擴展,以支持這些查詢樣式。
- 要使用這些新型查詢的原型,您可以訪問http://www.jinq.org
翻譯自: https://www.javacodegeeks.com/2014/03/java-8-friday-java-8-will-revolutionize-database-access.html
總結
以上是生活随笔為你收集整理的Java 8 Friday:Java 8将彻底改变数据库访问的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2018手机支付宝怎样解除实名认证?
- 下一篇: 621785开头是什么银行?