山一程--软件开发--数据--JPA Hibernate 查询

目的:精研 JPA Hibernate 的查询


1.thanks  for reference:

1>. <Java  persistence with hibernate, 2nd> chapter14 

 


1.概述:

1> 选择: from Item  ->  数据源, 类 或者  JPQL 中的数据库表名,  

Criteira 要求有 别名, from Item  i

要求有 查询根 Root<?>  i = Criteria.from(Item.class)

2> 限制  where 子句  从全部实例中限定

场景: Item 都有一个可嵌入的Image 持久化映射, 每个Image 文件名都是一个映射键, 以下查询会检索文件名中具有 .jpg 后缀的所有 Image 实例:

select value (img) from Item  i  join  i.images  img 

where key ( img)  like '%.jpg'

value() 操作符会返回Map 的值。 key() 返回键集。

3> 投影: 将1,2 查询到的数据, 返回给应用程序。  Select 子句


示例

1. mysql DDL DML

// insert data 

insert into  ITEM (`NAME`,`FIRST_NAME`,`LAST_NAME`) VALUES ("Foo","John","Howard");
insert into  ITEM(`NAME`,`FIRST_NAME`,`LAST_NAME`) VALUES ("Bar","Wilian","Sandi");
insert into  ITEM(`NAME`,`FIRST_NAME`,`LAST_NAME`) VALUES ("Baz","Stewen","Kind");

insert into  BID (`ITEM_ID`,`AMOUNT`) VALUES (1,99.00);
insert into  BID (`ITEM_ID`,`AMOUNT`) VALUES (1,100.00);
insert into  BID (`ITEM_ID`,`AMOUNT`) VALUES (1,101.00);
insert into  BID (`ITEM_ID`,`AMOUNT`) VALUES (2,4.99);
data

 2. application 

 


 

2. 记录要点:

1. 场景:无法在开发时完全指定该查询,且应用程序必须在 运行时动态创建。  --  CreateriaQuery API

例如:在应用程序中使用 许多复选框,输入框 和用户可以启用的开关来实现一个搜索蒙版界面, 必须从用户选中的搜索选项中动态创建一个数据库查询. 使用 JPQL 和字符串连接。难以编写和维护。

如果希望从特定持久化上下文中单独创建该查询, 可以从全局共享的 EntityManagerFactory 中获得 CriteriaBuilder.


多条件查询组合 Predicate

 


2. 外部化查询,可以将查询绑定到一个XML文件中,独立于任何Java类,较大的应用程序中常选用此技术,相较于将代码库分散在访问数据库的各个类中,在一些位置维护数百个查询会更容易.

@NamedQuery 和 @NamedNativeQuery 注解命名的查询, 只能在一个映射的类上放置这些注解.

查询名称必须在所有的类中是全局唯一的; 没有类或报名称会被自动作为前缀加到查询名称上.

XML 可能最常用, 在 orm.xml 元数据的任何 JPA <entity-mapping> 元素中 放置一个命名查询 ,将所有的命名查询隔离到自己的文件中 .可能想要相同的XML 映射文件来定义查询和一个特定类.

要将查询文本包装到一个 CDATA 指令中, 这样查询字符串中的 任何可能不经意被视作 XML 的字符串(例如小于 运算符)就不会让 XML 解析器混淆.

命名查询可以是 JPQL, 也可以是原生SQL查询.

<Hibernate in action> p326


3.投影

1.对于报告查询, 瞬时,便利方法:投影中的动态实例化  p350

DTO data transfer objects 

应用程序中有一个报告界面,其中需要显示一个列表中的一些数据, 希望显示所有的拍卖商品以及每次拍卖的结束时间.

不希望加载托管的 Item 实体实例, 因为没有数据会被修改:只读取数据.

1.编写 ItemSummary 的类,构造函数包含所有信息字段. DTO

 Criteria construct() 方法,  JPQL new

不可嵌套构造函数调用.

动态实例化一个应用场景: 简单数据复制, 

从数据库 中检索具有一些复制到构造函数中的值的一个“新”瞬时 Item,在应用程序中设置其他一些值,然后使用persis() 将它存储到数据库中.


DTO 不具有正确的构造函数,希望通过 setter 或字段从一个查询结果中填充, ResultTransformer , 聚合与分组. p376


 报告视图常用函数

聚合与分组  p355

1. count()  countDistinct() ; min() , max() , sum() , avg(),

在 select 子句中调用一个聚合函数, 而不是在 GROUP BY 子句中指定任何分组时, 就会将结果大大降低为单个行, 其中包含聚合后的值.

意味着缺少 GROUP BY 子句时, 任何包含一个聚合函数的 select 子句都必须仅包含聚合函数.

2.分组

聚合的 Group By 和 Having 子句.

任何 出现在Select 子句中的聚合函数之外的属性或别名, 都必须出现在Group by子句中.

SELECT 和 HAVING 子句遵循相同的规则:只有分组的属性可以出现在一个聚合函数之外.


难以理解却是关系模型最大的好处:联结任意数据的能力. p357

联结 会用两种或更多关系组合数据。在一个查询中联结数据 可以在单个查询中抓取几个关联的实例与集合.

例如:在与数据库交互中加载一个Item 及其所有的 bids。

内连接:


外联结通常用于动态抓取.

 

右外联结 : 如果没有一个一对多 Item#bids 集合, 就需要一个右外联结来检索所有的 Item 及其Bid实例.

需要从“另一” 端来驱动该查询: 多对一 Bid#item。


LinkedHashSet 传递List 来过滤重复的实例,且保留原来顺序.

DISTINCT 关键字去重, Fetch 急切抓取.

急动态抓取的注意事项:  p365

急抓取一个集合, 注意结合 DISTINCT 去重, 或内存中用LinkedHashSet

急抓取一个集合,则不能在数据库级别对结果集进行分页. Hibernater 会在内存中执行分页. 意味着所有 Item实例都会被加载到内存中,

每个都具有完全 初始化的 bids 集合,hibernate 会提供所请求的商品页.

并非所有商品都能放入内存中,期望在数据库中将结果传递给 应用程序之前就在数据库中产生分页!

不建议带有 setMaxResults() 或 setFirstResult() 选项的 fetch【collectionPath】,不期望逐页加载数据来修改它,

示例:显示几页商品且为每个商品显示出价次数,编写一个报告查询:

select i.id, i.name,  count(b)  from Item i  left join i.bids  b

group by i.id, i.nae

可以使用 setFirstResult()  和 setMaxResults()  通过数据库对该查询结果进行分页。

它比任何 Item 或 Bid 实例检索到内存中更高效. 


子查询

重要且强大. 是嵌入到另一个查询中的选择查询,通常是嵌入到 Select, From 或 Where 子句中.

JPA 支持 Where 子句中的子查询.

子查询是一项高级技术;具有子查询的查询通常只能用 联结和聚合 来重写。

一个相关子查询的性能开销类似于一个联结的开销,但不可能使用几个独立查询来重写一个相关子查询.

如果一个子查询返回多行,那么可以用量化来合并它。

量词限定符, ALL, ANY,  EXIST

 

posted @ 2023-06-03 19:08  君子之行  阅读(20)  评论(0)    收藏  举报