共计 5004 个字符,预计需要花费 13 分钟才能阅读完成。
自动写代码机器人,免费开通
Java 中怎么利用 Streams 对数据库进行查询操作,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。
示例数据库
我们使用的示例数据库是 Sakila。它有 Film(影片), Actor(演员), Category(类别)等表格,下载地址:
https://dev.mysql.com/doc/index-other.html
。
步骤一:连接数据库
我们使用
Speedment Initializer
配置 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`
`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`
`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`
`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();
关于 Java 中怎么利用 Streams 对数据库进行查询操作问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注丸趣 TV 行业资讯频道了解更多相关知识。
向 AI 问一下细节