如何使用Java Streams進行資料庫查詢?
本文介紹瞭如何編寫能夠處理現有資料庫資料的Java應用程式,而無需編寫單行SQL(或類似語言)程式碼,也無需浪費時間將所有的內容組合在一起。在您的應用程式準備就緒之後,您可以透過新增兩行程式碼,使用in-JVM-acceleration加速效能。
本文,我們使用Speedment框架,可以直接從資料庫模式生成程式碼,並可以自動將Java Streams生成SQL,您可以使用Java編寫程式碼。
示例資料庫
我們使用的示例資料庫是Sakila。它有Film(影片), Actor(演員), Category(類別)等表格,下載地址: https://dev.mysql.com/doc/index-other.html 。
步驟一:連線資料庫
我們使用 配置pom.xml檔案,點選下載後,將得到一個帶有自動生成Main.java檔案的專案資料夾。
然後,解壓資料夾zip.,開啟命令列,然後轉到pO.xml檔案所在的位置。輸入以下命令:
mvn speedment:tool
Speedment將被啟動,會提示您輸入授權碼。選擇“Start Free”,您將獲得免費許可。然後便可以連線資料庫開始使用。
步驟二:生成程式碼
當資料庫開始載入schema data時,便可以點選"Generate"生成完整的Java域模型。
步驟三:編寫應用程式程式碼
步驟二中還會自動生成一個Speedment的生成器。開啟Main.java檔案,將main()方法中的程式碼替換成以下程式碼:
SakilaApplication app = new SakilaApplicationBuilder() .withPassword("sakila-password") // Replace with your own password .build();
接下來,我們將編寫一個列印出所有影片的應用程式。當然這只是一個小程式,我們還要對其進行改進。
// Obtains a FilmManager that allows us to // work with the "film" table FilmManager films = app.getOrThrow(FilmManager.class); // Create a stream of all films and print // each and every film films.stream() .forEach(System.out::println);
執行時,Java stream將自動生成SQL。為了檢視SQL程式碼,需要修改Application Builder,並使用STREAM日誌型別開啟日誌記錄。
SakilaApplication app = new SakilaApplicationBuilder() .withPassword("sakila-password") .withLogging(ApplicationBuilder.LogType.STREAM) .build();
以下是執行應用程式時的SQL程式碼:
SELECT `film_id`,`title`,`description`,`release_year`, `language_id`,`original_language_id`,`rental_duration`,`rental_rate`, `length`,`replacement_cost`,`rating`,`special_features`,`last_update` FROM `sakila`.`film`, values:[]
SQL程式碼會因您選擇的資料庫型別而異(例如MySQL,MariaDB,PostgreSQL,Oracle,MS SQL Server,DB2,AS400等),且這些變化都是自動的。
上面的程式碼將產生以下輸出(簡潔為主)
FilmImpl { filmId = 1, title = ACADEMY DINOSAUR, ..., length = 86, ... } FilmImpl { filmId = 2, title = ACE GOLDFINGER, ..., length = 48, ...} FilmImpl { filmId = 3, title = ADAPTATION HOLES, ..., length = 50, ...} ...
步驟四:使用過濾器
Speedment流包括過濾器在內的所有流操作。假設我們只想過濾掉那些超過60分鐘的影片,可以透過以下程式碼來實現:
films.stream() .filter(Film.LENGTH.greaterThan(60)) .forEach(System.out::println);
生成SQL:
SELECT `film_id`,`title`,`description`,`release_year`, `language_id`,`original_language_id`,`rental_duration`,`rental_rate`, `length`,`replacement_cost`,`rating`,`special_features`, `last_update` FROM `sakila`.`film` WHERE (`length` > ?), values:[60]
生成輸出:
FilmImpl { filmId = 1, title = ACADEMY DINOSAUR, ..., length = 86, ... } FilmImpl { filmId = 4, title = AFFAIR PREJUDICE, ..., length = 117, ...} FilmImpl { filmId = 5, title = AFRICAN EGG, ... length = 130, ...}
可以透過組合過濾器來建立更復雜的表示式,如下所示:
films.stream() .filter( Film.LENGTH.greaterThan(60).or(Film.LENGTH.lessThan(30)) ) .forEach(System.out::println);
這將回收掉那些不到30分鐘或者超過一小時的影片。這時檢查您的日誌檔案,您將發現這個流已生成SQL。
步驟五:定義元素的順序
預設情況下,出現在流中的元素是未被定義的。想要定義一個特定順序,您需要將SORTED()操作應用到這樣的流:
films.stream() .filter(Film.LENGTH.greaterThan(60)) .sorted(Film.TITLE) .forEach(System.out::println);
生成SQL
SELECT `film_id`,`title`,`description`,`release_year`, `language_id`,`original_language_id`,`rental_duration`,`rental_rate`, `length`,`replacement_cost`,`rating`,`special_features`, `last_update` FROM `sakila`.`film` WHERE (`length` > ?) ORDER BY `length` ASC, values:[60]
生成輸出:
FilmImpl { filmId = 77, title = BIRDS PERDITION,..., length = 61,...} FilmImpl { filmId = 106, title = BULWORTH COMMANDMENTS,..., length = 61,} FilmImpl { filmId = 114, title = CAMELOT VACATION,..., length = 61,..} ...
您還可以組合多種分類機來定義主順序、次順序等。
films.stream() .filter(Film.LENGTH.greaterThan(60)) .sorted(Film.LENGTH.thenComparing(Film.TITLE.reversed())) .forEach(System.out::println);
這將按照LENGTH順序(升序)和TITLE順序(降序)對影片元素進行排序。您可以對數量欄位進行任意組合。
注意:如果您按升序組成兩個或兩個以上欄位時,你應該使用.comparator(). I.e.欄位方法。例如:sorted(Film.LENGTH.thenComparing(Film.TITLE.comparator()))。
步驟六:避免大物件塊(Large Object Chunks)
人們一般會對結果進行分頁來避免使用不必要的大物件塊(Large Object Chunks)。假設我們希望在每頁看到50個元素,我們可以透過以下程式碼來實現:
private static final int PAGE_SIZE = 50; public static <T> Stream<T> page( Manager<T> manager, Predicate<? super T> predicate, Comparator<? super T> comparator, int pageNo ) { return manager.stream() .filter(predicate) .sorted(comparator) .skip(pageNo * PAGE_SIZE) .limit(PAGE_SIZE); }
該方法可以使用任意過濾器對任意表進行隨意排序。
例如,呼叫:
page(films, Film.LENGTH.greaterThan(60), Film.TITLE, 3)
將回收掉那些超過60分鐘的影片流,並按照第三頁的標題進行排序(即,跳過150部影片並顯示以下50部影片)。
生成SQL
SELECT `film_id`,`title`,`description`,`release_year`, `language_id`,`original_language_id`,`rental_duration`,`rental_rate`, `length`,`replacement_cost`,`rating`,`special_features`, `last_update` FROM `sakila`.`film` WHERE (`length` > ?) ORDER BY `title` ASC LIMIT ? OFFSET ?, values:[60, 50, 150]
生成輸出
FilmImpl { filmId = 165, title = COLDBLOODED DARLING, ... length = 70,...} FilmImpl { filmId = 166, title = COLOR PHILADELPHIA, ..., length = 149... } FilmImpl { filmId = 167, title = COMA HEAD, ... length = 109,...} ...
同樣,如果我們使用了另一種資料庫型別,那麼SQL程式碼就會不同。
步驟七: In-JVM-Memory加速
由於您在初始化程式中使用了標準配置,所以In-JVM-memory加速在POM.XML檔案中就被啟動。如果要啟用應用程式中的加速,只需要將初始程式碼修改成如下程式碼:
SakilaApplication app = new SakilaApplicationBuilder() .withPassword("sakila-password") .withBundle(InMemoryBundle.class) .build(); // Load data from the database into an in-memory snapshot app.getOrThrow(DataStoreComponent.class).load();
現在,表流將直接在RAM中被提供,而不是生成SQL查詢。記憶體索引也將加速過濾、排序和跳過。記憶體表和索引都儲存在堆外,避免了垃圾回收的延遲。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31542119/viewspace-2214198/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- JPA使用Specification pattern 進行資料查詢
- java中資料庫查詢,搭配簡單的圖形介面進行查詢Java資料庫
- langchain_chatchat+ollama部署本地知識庫,聯網查詢以及對資料庫(Oracle)資料進行查詢LangChain資料庫Oracle
- 利用GeoIP資料庫及API進行地理定位查詢資料庫API
- 使用Redis和Java進行資料庫快取RedisJava資料庫快取
- 使用Java和Flyway進行資料庫版本控制Java資料庫
- 分庫資料如何查詢統計
- 如何使用PL/SQL進行分級查詢WPSQL
- 使用Redis和Java進行資料庫快取 - DZone資料庫RedisJava資料庫快取
- 資料庫查詢資料庫
- 資料庫 - 資料查詢資料庫
- 資料庫資料的查詢----連線查詢資料庫
- day95:flask:SQLAlchemy資料庫查詢進階&關聯查詢FlaskSQL資料庫
- Java 8 Streams 中的資料庫 CRUD 操作Java資料庫
- 改進資料庫效能-SQL查詢優化資料庫SQL優化
- 如何使用 Milvus 向量資料庫實現實時查詢資料庫
- Django中views資料查詢使用locals()函式進行優化DjangoView函式優化
- 資料庫查詢第5到8行的資料資料庫
- 資料庫高階查詢之子查詢資料庫
- Java ——MongDB 插入資料、 模糊查詢、in查詢Java
- 使用MDX進行環比查詢
- 如何抽取Oracle資料到文字文件進行查詢NAOracle
- 求助:資料庫查詢資料庫
- ThinkPHP 資料庫查詢PHP資料庫
- 查詢資料庫大小資料庫
- 資料庫排序查詢資料庫排序
- Jemter查詢資料庫資料庫
- java 查詢資料庫並生成多層childrenJava資料庫
- 資料庫 - 連線查詢、巢狀查詢、集合查詢資料庫巢狀
- 如何使用 Eloquent 在兩個日期之間進行查詢?
- 資料庫基礎查詢--單表查詢資料庫
- 資料庫查詢優化:巢狀查詢資料庫優化巢狀
- 如何查詢和管理織夢CMS資料庫資料庫
- 如何在Django ORM中進行not查詢?DjangoORM
- mysql 資料庫或者表空間使用查詢MySql資料庫
- .NET CORE 下如何使用國產資料庫進行 開發資料庫
- 如何使用帝國CMS進行資料庫匯出操作?資料庫
- Java 中如何使用 SQL 查詢 TXTJavaSQL