java - 如何使用旧的休眠标准进行批处理?
问题描述
我仍在使用旧的org.hibernate.Criteria
,并且对获取模式越来越感到困惑。在各种查询中,我需要以下所有变体,因此无法通过注释对其进行控制。我只是将所有内容切换为@ManyToOne(fetch=FetchType.LAZY)
,否则,查询中的任何内容都不会更改。
到目前为止,我能找到的要么涉及 HQL 或 JPA2,要么只提供两种选择,但我需要它来满足旧标准和(至少)以下三种情况:
- 执行 JOIN,并从两个表中获取。除非数据过于冗余(例如,主数据很大或在结果中重复多次),否则这是可以的。在 SQL 中,我会写
SELECT * FROM item JOIN order on item.order_id = order.id
WHERE ...;
- 执行 JOIN,从第一个表中获取,然后与另一个表分离。这通常是上一个查询的更有效的变体。在 SQL 中,我会写
SELECT item.* FROM item JOIN order on item.order_id = order.id
WHERE ...;
SELECT order.* FROM order WHERE ...;
- 执行 JOIN,但不获取连接的表。这很有用,例如,对于基于其他表的数据进行排序。在 SQL 中,我会写
SELECT item.* FROM item JOIN order on item.order_id = order.id
WHERE ...
ORDER BY order.name, item.name;
看起来如果没有明确指定fetch=FetchType.LAZY
,一切都会像第一种情况一样被急切地获取,这有时太糟糕了。我想,使用Criteria#setFetchMode
,我可以得到第三种情况。我还没有尝试过,因为我仍然错过了第二种情况。我知道这是有可能的,因为有@BatchSize
注释。
- 我对上述内容正确吗?
- 有没有办法用旧标准获得第二个案例?
更新
看起来使用createAlias()
线索可以急切地获取所有内容。有一些重载允许指定JoinType
,但我需要指定 fetch 类型。现在,我更加困惑了。
解决方案
Yes you can satisfy all three cases using FetchType.LAZY, BatchSize, the different fetch modes, and projections (note I just made up a 'where' clause with Restrictions.like("name", "%s%")
to ensure that I retrieved many rows):
Do a JOIN, and fetch from both tables.
Because the order of an item is FetchType.LAZY, the default fetch mode will be 'SELECT' so it just needs to be set as 'JOIN' to fetch the related entity data from a join rather than separate query:
Session session = entityManager.unwrap(org.hibernate.Session.class); Criteria cr = session.createCriteria(Item.class); cr.add(Restrictions.like("name", "%s%")); cr.setFetchMode("order", FetchMode.JOIN); List results = cr.list(); results.forEach(r -> System.out.println(((Item)r).getOrder().getName()));
The resulting single SQL query:
select this_.id as id1_0_1_, this_.name as name2_0_1_, this_.order_id as order_id3_0_1_, order2_.id as id1_1_0_, order2_.name as name2_1_0_ from item_table this_ left outer join order_table order2_ on this_.order_id=order2_.id where this_.name like ?
Do a JOIN, fetch from the first table and the separately from the other.
Leave the fetch mode as the default 'SELECT', create an alias for the order to use it's columns in sorting, and use a projection to select the desired subset of columns including the foreign key:
Session session = entityManager.unwrap(org.hibernate.Session.class); Criteria cr = session.createCriteria(Item.class); cr.add(Restrictions.like("name", "%s%")); cr.createAlias("order", "o"); cr.addOrder(org.hibernate.criterion.Order.asc("o.id")); cr.setProjection(Projections.projectionList() .add(Projections.property("id"), "id") .add(Projections.property("name"), "name") .add(Projections.property("order"), "order")) .setResultTransformer(org.hibernate.transform.Transformers.aliasToBean(Item.class)); List results = cr.list(); results.forEach(r -> System.out.println(((Item)r).getOrder().getName()));
The resulting first SQL query:
select this_.id as y0_, this_.name as y1_, this_.order_id as y2_ from item_table this_ inner join order_table o1_ on this_.order_id=o1_.id where this_.name like ? order by o1_.id asc
and subsequent batches (note I used
@BatchSize(value=5)
on the Order class):select order0_.id as id1_1_0_, order0_.name as name2_1_0_ from order_table order0_ where order0_.id in ( ?, ?, ?, ?, ? )
Do a JOIN, but do not fetch the joined table.
Same as the previous case, but don't do anything to prompt the loading of the lazy-loaded orders:
Session session = entityManager.unwrap(org.hibernate.Session.class); Criteria cr = session.createCriteria(Item.class); cr.add(Restrictions.like("name", "%s%")); cr.createAlias("order", "o"); cr.addOrder(Order.asc("o.id")); cr.setProjection(Projections.projectionList() .add(Projections.property("id"), "id") .add(Projections.property("name"), "name") .add(Projections.property("order"), "order")) .setResultTransformer(org.hibernate.transform.Transformers.aliasToBean(Item.class)); List results = cr.list(); results.forEach(r -> System.out.println(((Item)r).getName()));
The resulting single SQL query:
select this_.id as y0_, this_.name as y1_, this_.order_id as y2_ from item_table this_ inner join order_table o1_ on this_.order_id=o1_.id where this_.name like ? order by o1_.id asc
My entities for all cases remained the same:
@Entity
@Table(name = "item_table")
public class Item {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@ManyToOne(fetch = FetchType.LAZY)
private Order order;
// getters and setters omitted
}
@Entity
@Table(name = "order_table")
@BatchSize(size = 5)
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
// getters and setters omitted
}
推荐阅读
- reactjs - 一个带有 react.js 的简单表单组件。但是onsubmit所有字段总是空的?
- postgresql - 从 rsync 克隆 PostgreSQL 11
- sql - 如何在表中创建缺少属性的查询?
- reactjs - 在反应组件中,无法使用退格从输入框中清除最后一个整数
- git - 在 Azur DevOps 中将构建服务“用户”添加到“项目集合构建服务”
- java - 我可以在 java 方法中模拟休息调用吗
- java - 为什么 AVG 函数的结果为空?
- reactjs - 如何解决第一个渲染中的问题?
- c-preprocessor - 预处理器:为什么要仔细检查是否需要包含头文件?
- nginx - NGINX。OpenShift 集群之间的负载平衡。如何获取上游服务器的名称?