Speedment - Stream

準備

  • MySQL 的 sakila 數據庫
  • 在 Maven 項目中,用 Speedment 生成 sakila 對應的代碼

Main

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();
}
  1. 構建app
  2. 獲取實體manager
  3. 完成邏輯
  4. 關閉app

計數 count

// 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

查詢 select

// 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 也是能夠的,可是若是要進行復雜、可能會因需求而改動的統計(聚合)操做,我認爲,仍是代碼更舒服一點,同時數據庫也不用承擔密集的計算。框架

優化 optimize

app中的 java stream 都是陳述性的結構,Speedment runtime 框架會對查詢進行優化。優化

例如對於如下查詢,由於最終須要的是計數,Speedment 會將毫無心義的mapsort操做砍掉,而後把任務所有扔給數據庫。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]

分組 group by

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.

聯表 join

根據演員名字查詢電影,若是用 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
 // 省略
 ...
相關文章
相關標籤/搜索