山一程--软件开发--数据--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);
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


浙公网安备 33010602011771号