成为Java流大师(第4部分):数据库流

3 月,跳不动了?>>> hot3.png

流

您几乎可以看到数据在流动...

SQL一直是一种声明性语言,而Java长期以来势在必行。Java流改变了游戏规则。通过本动手文章编写您的方式,并学习如何使用Java流对RDBMS数据库执行声明性查询,而无需编写任何SQL代码。您会发现,Java流和SQL命令的动词之间有着惊人的相似性。

不是您要找的东西?看看  使用Java Streams查询数据库

本文是五分之四,另外还有一个GitHub存储库,其中包含每个单元的说明和练习。

数据库流

当您熟悉Streams的操作时,您可能已经注意到与SQL构造的相似之处。它们中的一些或多或少具有与Stream操作的直接映射,例如LIMITCOUNT开源项目Speedment利用这种相似性,使用纯Java提供对任何关系数据库的类型安全访问。

4_1.png

下表显示了Speedment如何在SQL流与Java流之间进行映射。

我们是Speedment开源项目的贡献者,我们将描述Speedment如何允许我们使用数据库作为流源,并使用来自任何数据库表的行向管道馈送数据。

4_2.png

如上图所示,Speedment将建立与数据库的连接,然后可以将数据传递给应用程序。不需要为数据库条目编写任何代码,因为Speedment会分析基础数据库并自动生成域模型所需的所有实体类。当您不必为要使用的每个表手动编写和维护实体类时,它可以节省大量时间。

Sakila数据库

为了本文和练习的方便,我们使用MySQL示例数据库Sakila作为我们的数据源。Sakila数据库为老式电影租赁业务建模,因此包含诸如Film和Actor之类的表。数据库实例已部署在云中,并且可以公开访问。

速度管理器

在Speedment中,数据库表的句柄称为Manager。管理器是自动生成的代码的一部分。

4_3.png


Manager充当数据库表的句柄,并且可以充当流源。在这种情况下,每一行都对应一个Film实例。

一个Manager在Speedment是通过调用实例:

 
FilmManager  电影 =  速度。getOrThrow(FilmManager。);
 

 

注意:Speedment是可以从ApplicationBuilder获得的实例(在下一篇文章中对此主题有更多的了解)。

如果FilmManager::stream调用,则结果是a Stream,我们可以自由地对其应用任何中间或终端操作。首先,我们将收集列表中的所有行。

 
列出< 电影>  allFilms  =  电影。流()。收集(toList());
 
FilmImpl { filmId  =  1,标题 =  ACADEMY  DINOSAUR,…
 
FilmImpl { filmId  =  2,标题 =  ACE  GOLDFINGER,…
 
FilmImpl { filmId  =  3,标题 =  适应 HOLES,...
 
 

 

过滤和计数

让我们看一个简单的示例,该示例输出评级为“ PG-13”的电影数量。就像常规Stream影片一样,我们可以过滤出具有正确评分的电影,然后对这些作品进行计数。

 
 pg13FilmCount  =  电影。流()
 
   。滤镜(电影。额定。等于(“ PG-13”))
 
   。数();
 
 
 
pg13FilmCount:195
 

 

Speedment自定义实现Streams后的一个重要属性是,流能够通过自省来优化自己的管道。看起来Stream会遍历表的所有行,但事实并非如此。相反,Speedment能够将管道转换为传递给数据库的优化SQL查询。这意味着仅将相关的数据库条目提取到流中。因此,在上面的示例中,该流将自动呈现为类似于“ SELECT ... FROM film WHERE rating ='PG-13'”的SQL

这种自省要求将匿名lambda的任何使用(不包含与目标列相关的任何元数据)替换为Speedment Fields中的谓词。在这种情况下,当且仅当该电影的评分为PG-13时,才返回将在每部电影上进行测试的Film.RATING.equal("PG-13")Predicate并返回true。

虽然,这并不妨碍我们将谓词表示为:

 
。过滤器(˚F  - >  ˚F。getRating。()等于(“PG-13” ))
 

 

但这将迫使Speedment提取表中的所有行,然后应用谓词,因此建议这样做。

寻找最长的电影

这是一个示例,该示例使用带有-的max-operator在数据库中找到最长的电影Field Film.LENGTH

 
可选的< Film >  longestFilm  =  电影。流()
 
   。最大值(薄膜。LENGTH);
 
 
 
最长电影:
 
可选 [ FilmImpl { filmId  =  141,标题 =  CHICAGO  NORTH,长度 =  185,...}]
 

 

寻找三部短片

找到三部短片(我们定义为短于<= 50分钟)可以通过过滤掉50分钟或更短的任何片并挑选出前三个结果来完成。该示例中的谓词查看“长度”列的值,并确定该值是否小于或等于50。

 
列出< 电影>  threeShortFilms  =  电影。流()
 
    。过滤器(电影。LENGTH。lessOrEqual(50))
 
    。极限(3
 
    。收集(toList());
 
threeShortFilms:[
 
    FilmImpl { filmId  =  2,长度 =  48,..},
 
    FilmImpl { filmId  =  3,长度 =  50,… },
 
    FilmImpl { filmId  =  15,长度 =  46,...}]
 

 

分页分页

如果要在网站或应用程序中显示所有电影,我们可能希望对项目进行分页,而不是一次(可能)加载数千个条目。这可以通过结合操作skip()和来完成limit()。在下面的示例中,假设每个“页面”包含25个条目,我们将收集第二页的内容。回想一下,Streams不能保证元素的特定顺序,这意味着我们需要使用sorted-operator定义一个顺序才能使其按预期工作。

 
列出< 电影>  filmsSortedByLengthPage2  =  电影。流()
 
    。分类(电影。长度)
 
    。跳过(25  *  1
 
    。极限(25
 
    。收集(toList());
 
filmsSortedByLengthPage2:
 
[ FilmImpl { filmId  =  430,长度 =  49,… },… ]
 


注意:查找第n页的内容是通过跳过(25 *(n-1))完成的。
注意2:此流将自动呈现为“ SELECT ... FROM film ORDER BY length ASC LIMIT?OFFSET?,值:[25,25]”

以“ A”开头的电影,按长度排序

我们可以轻松地找到任何以大写字母“ A”开头的电影,并根据其长度(以最短的电影为首)对它们进行排序,如下所示:

 
列出< 电影>  filmsTitleStartsWithA  =  电影。流()
 
   。过滤器(电影。TITLE。startsWith(“A” ))
 
   。分类(电影。长度)
 
   。收集(收藏家。toList());
 
filmsTitleStartsWithA:[
 
    FilmImpl { filmId = 15,标题= ALIEN  CENTRE,…,等级= NC - 17,长度 =  46
 
    FilmImpl { filmId = 2,标题= ACE  GOLDFINGER,…,等级= G,长度 =  48
 
… ]
 

 

计算胶片长度的频率表

我们还可以利用groupingBy运算符根据其长度对存储桶中的胶片进行排序,并计算每个存储桶中的胶片总数。这将创建一个所谓的胶片长度频率表。

 
映射< ShortLong >  frequencyTableOfLength  =  电影。流()
 
    。收集(收藏家。groupingBy(
 
        电影。长度。asShort(),
 
        数()
 
    ));
 
frequencyTableOfLength:{ 46 = 547 = 748 = 1149 = 5,... }
 

 

练习题

对于本周的练习,您无需担心连接自己的数据库。相反,我们已经提供了到云中Sakila数据库实例的连接。像往常一样,练习可以位于该GitHub库。本文的含量足以解决这就是所谓的第四单元MyUnit4Database。相应的Unit4DatabaseInterface包含JavaDocs,它们描述了中方法的预期实现MyUnit4Database

 
公共 接口 Unit4Database {
 
 
 
   / **
 
    *返回数据库中的影片总数。
 
    *
 
    * @param电影实体的电影经理
 
    * @返回数据库中的电影总数
 
    * /
 
   long  countAllFilms(FilmManager  电影);
 

4_4.png

提供的测试(例如Unit4MyDatabaseTests)将用作自动评分工具,让您知道您的解决方案是否正确。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值