public static void main(String... params) { SakilaApplication app = new SakilaApplicationBuilder() .withPassword("123456") .withLogging(ApplicationBuilder.LogType.STREAM) .build(); FilmManager films = app.getOrThrow(FilmManager.class); ActorManager actors = app.getOrThrow(ActorManager.class); FilmActorManager filmActors = app.getOrThrow(FilmActorManager.class); // your application logic here app.stop(); }
app
manager
app
// your application logic here long count = films.stream() .filter(Film.RATING.equal("PG-13")) .count();
輸出結果爲java
2017-11-18T09:41:50.141Z DEBUG [main] (#STREAM) - SELECT COUNT(*) FROM (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 (`sakila`.`film`.`rating` = ? COLLATE utf8_bin)) AS A, values:[PG-13] There are 223 PG-13 films in the DB
這裏,Speedment 將計數的工做所有交給了數據庫引擎執行。sql
// your application logic here Scanner scn = new Scanner(System.in); System.out.println("Please enter Film ID "); final int id = Integer.decode(scn.nextLine().trim()); final Optional<String> title = films.stream() .filter(Film.FILM_ID.equal(id)) // find the films we are looking for .map(Film::getTitle) // switch from a stream of films to one of titles .findAny(); // we want the first and only match for this unique key if (title.isPresent()) { System.out.format("Film ID %d has title %s.", id, title.get()); } else { System.out.format("Film ID not found.", id); }
輸出結果爲數據庫
Please enter Film ID 1 2017-11-18T09:51:27.805Z DEBUG [main] (#STREAM) - 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 (`sakila`.`film`.`film_id` = ?), values:[1] Film ID 1 has title ACADEMY DINOSAUR.
這是一個最多見的查詢,根據id查詢某個屬性,Speedment 將查詢的任務交給數據庫引擎,將對數據的處理交給JVM。app
固然,直接寫好 sql 也是能夠的,可是若是要進行復雜、可能會因需求而改動的統計(聚合)操做,我認爲,仍是代碼更舒服一點,同時數據庫也不用承擔密集的計算。框架
在app
中的 java stream 都是陳述性的結構,Speedment runtime 框架會對查詢進行優化。優化
例如對於如下查詢,由於最終須要的是計數,Speedment 會將毫無心義的map
和sort
操做砍掉,而後把任務所有扔給數據庫。ui
long count = films.stream() .filter(Film.RATING.equal("PG-13")) .filter(Film.LENGTH.greaterOrEqual(75)) .map(Film::getTitle) .sorted() .count(); System.out.printf("Found %d films", count);
運行結果this
2017-11-18T10:30:50.312Z DEBUG [main] (#STREAM) - SELECT COUNT(*) FROM (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 (`sakila`.`film`.`rating` = ? COLLATE utf8_bin) AND (`sakila`.`film`.`length` >= ?)) AS A, values:[PG-13, 75]
films.stream() .collect(Collectors.groupingBy(Film.RATING.getter(), Collectors.counting())) .forEach( (rating, count) -> System.out.printf("There are %d %s rated films.%n", count, rating) );
2017-11-18T10:41:46.580Z DEBUG [main] (#STREAM) - 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:[] There are 223 PG-13 rated films. There are 195 R rated films. There are 210 NC-17 rated films. There are 178 G rated films. There are 194 PG rated films.
根據演員名字查詢電影,若是用 sql 那就是聯表查詢,可是使用 Speedment 的話,須要寫兩部分代碼。日誌
// 接收參數 System.out.println("Please enter actor last name "); final String actorName = scn.nextLine().trim(); // 先根據演員name查出演員的id Set<Integer> selectedActorIds = actors.stream() .filter(Actor.LAST_NAME.equalIgnoreCase(actorName)) .mapToInt(Actor.ACTOR_ID.getter()) // turning the stream into a stream of actor IDs .boxed() // turning IntStream into Stream<Integer> .collect(toSet()); // 2. 根據演員id關聯的電影id,查出電影名稱 if (selectedActorIds.isEmpty()) { System.out.println("No actor with last name " + actorName + " found."); } else { System.out.println("Films with actor with last name " + actorName + ":"); filmActors.stream() .filter(FilmActor.ACTOR_ID.in(selectedActorIds)) .map(films.finderBy(FilmActor.FILM_ID)) // the stream of films we are looking for .map(Film.TITLE.getter()) // the stream of film titles .sorted() .forEach(title -> System.out.println(" " + title)); }
結果以下,一會兒查出來有點多,對 Speedment 惟一的偏好,就是邏輯清楚,我喜歡邏輯的思惟,而不是集合的思惟(sql),可是日誌中出現了好多 SELECT
語句, 我想這應該是.map(films.finderBy(FilmActor.FILM_ID))
的功勞,若是不用這個map
,應該會好一點。code
Please enter actor last name BRODY 2017-11-18T11:14:26.663Z DEBUG [main] (#STREAM) - SELECT `actor_id`,`first_name`,`last_name`,`last_update` FROM `sakila`.`actor` WHERE (`sakila`.`actor`.`last_name` = ? COLLATE utf8_general_ci), values:[brody] Films with actor with last name BRODY: 2017-11-18T11:14:26.704Z DEBUG [main] (#STREAM) - SELECT `actor_id`,`film_id`,`last_update` FROM `sakila`.`film_actor` WHERE (`sakila`.`film_actor`.`actor_id` IN (?,?)), values:[39, 159] 2017-11-18T11:14:26.714Z DEBUG [main] (#STREAM) - 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 (`sakila`.`film`.`film_id` = ?), values:[71] 2017-11-18T11:14:26.726Z DEBUG [main] (#STREAM) - 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 (`sakila`.`film`.`film_id` = ?), values:[73] 2017-11-18T11:14:26.729Z DEBUG [main] (#STREAM) - 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 (`sakila`.`film`.`film_id` = ?), values:[168] // 省略查詢語句... AMELIE HELLFIGHTERS BILKO ANONYMOUS // 省略電影名稱...
優化後的代碼及輸出以下
// 1. 根據 actor name 查詢 actor id System.out.println("Please enter actor last name "); final String actorName = scn.nextLine().trim(); Set<Integer> selectedActorIds = actors.stream() .filter(Actor.LAST_NAME.equalIgnoreCase(actorName)) .mapToInt(Actor.ACTOR_ID.getter()) .boxed() .collect(toSet()); // 2. 根據 actor id 查詢 film ids System.out.println("Films with actor with last name " + actorName + ":"); Set<Integer> filmIds = filmActors.stream() .filter(FilmActor.ACTOR_ID.in(selectedActorIds)) .mapToInt(FilmActor.FILM_ID.getter()) .boxed() .collect(toSet()); // 3. 根據 film ids 查詢 film names films.stream() .filter(Film.FILM_ID.in(filmIds)) .map(Film.TITLE.getter()) .forEach(title -> System.out.println(" " + title));
Please enter actor last name GUINESS 2017-11-18T11:32:14.529Z DEBUG [main] (#STREAM) - SELECT `actor_id`,`first_name`,`last_name`,`last_update` FROM `sakila`.`actor` WHERE (`sakila`.`actor`.`last_name` = ? COLLATE utf8_general_ci), values:[guiness] Films with actor with last name GUINESS: 2017-11-18T11:32:14.561Z DEBUG [main] (#STREAM) - SELECT `actor_id`,`film_id`,`last_update` FROM `sakila`.`film_actor` WHERE (`sakila`.`film_actor`.`actor_id` IN (?,?,?)), values:[1, 179, 90] 2017-11-18T11:32:14.570Z DEBUG [main] (#STREAM) - 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 (`sakila`.`film`.`film_id` IN (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)), values:[384, 1, 385, 769, 2, 771, 131, 901, 262, 391, 520, 650, 11, 140, 529, 277, 406, 23, 663, 24, 25, 27, 924, 925, 542, 159, 415, 291, 931, 676, 166, 939, 811, 303, 433, 817, 438, 566, 442, 698, 832, 960, 65, 193, 451, 197, 838, 970, 330, 586, 588, 463, 976, 980, 212, 468, 852, 85, 855, 858, 732, 605, 353, 737, 100, 868, 361, 489, 106, 363, 749, 109, 880, 499, 374, 633, 506, 250, 635, 509] ACADEMY DINOSAUR ACE GOLDFINGER // 省略 ...