Hibernate –获取策略示例

Hibernate很少有获取策略来优化Hibernate生成的select语句,从而使其尽可能高效。 在映射关系中声明了获取策略,以定义Hibernate如何获取其相关集合和实体。

提取策略

有四种获取策略

1. fetch-“ join” =禁用延迟加载,始终加载所有集合和实体。
2. fetch-“选择”(默认)=延迟加载所有集合和实体。
3. batch-size =“ N” =最多提取“ N”个集合或实体,*不记录*。
4. fetch-“ subselect” =将其集合分组为一个sub select语句。

有关详细说明,您可以查看Hibernate文档

提取策略示例

这是获取策略演示的“一对多关系”示例。 股票属于许多股票每日记录。

在XML文件中声明提取策略的示例

...
<hibernate-mapping>
    <class name="com.mkyong.common.Stock" table="stock">
        <set name="stockDailyRecords"  cascade="all" inverse="true" 
            table="stock_daily_record" batch-size="10" fetch="select">
            <key>
                <column name="STOCK_ID" not-null="true" />
            </key>
            <one-to-many class="com.mkyong.common.StockDailyRecord" />
        </set>
    </class>
</hibernate-mapping>

在注释中声明获取策略的示例

...
@Entity
@Table(name = "stock", catalog = "mkyong")
public class Stock implements Serializable{
...
	@OneToMany(fetch = FetchType.LAZY, mappedBy = "stock")
	@Cascade(CascadeType.ALL)
	@Fetch(FetchMode.SELECT)
        @BatchSize(size = 10)
	public Set<StockDailyRecord> getStockDailyRecords() {
		return this.stockDailyRecords;
	}
...
}

让我们探索获取策略如何影响Hibernate生成的SQL语句。

1. fetch =“ select”或@Fetch(FetchMode.SELECT)

这是默认的获取策略。 它启用了所有相关集合的延迟加载。 让我们看一个例子……

//call select from stock
Stock stock = (Stock)session.get(Stock.class, 114); 
Set sets = stock.getStockDailyRecords();
        
//call select from stock_daily_record
for ( Iterator iter = sets.iterator();iter.hasNext(); ) { 
      StockDailyRecord sdr = (StockDailyRecord) iter.next();
      System.out.println(sdr.getDailyRecordId());
      System.out.println(sdr.getDate());
}

输出量

Hibernate: 
    select ...from mkyong.stock
    where stock0_.STOCK_ID=?

Hibernate: 
    select ...from mkyong.stock_daily_record
    where stockdaily0_.STOCK_ID=?

Hibernate生成了两个select语句

1.选择语句以检索库存记录– session.get(Stock.class,114)
2.选择与其相关的集合– sets.iterator()

2. fetch =“ join”或@Fetch(FetchMode.JOIN)

“ join”获取策略将禁用所有相关集合的延迟加载。 让我们看一个例子……

//call select from stock and stock_daily_record
Stock stock = (Stock)session.get(Stock.class, 114); 
Set sets = stock.getStockDailyRecords();

//no extra select
for ( Iterator iter = sets.iterator();iter.hasNext(); ) { 
      StockDailyRecord sdr = (StockDailyRecord) iter.next();
      System.out.println(sdr.getDailyRecordId());
      System.out.println(sdr.getDate());
}

输出量

Hibernate: 
    select ...
    from
        mkyong.stock stock0_ 
    left outer join
        mkyong.stock_daily_record stockdaily1_ 
            on stock0_.STOCK_ID=stockdaily1_.STOCK_ID 
    where
        stock0_.STOCK_ID=?

Hibernate仅生成一个select语句,它在初始化Stock时检索其所有相关集合。 – session.get(Stock.class,114)

1.选择语句以检索“库存记录”,并将其相关集合外联。

3. batch-size =“ 10”或@BatchSize(size = 10)

许多Hibernate开发人员总是误解这种“批量”获取策略。 让我们在这里看到*误解*概念...

Stock stock = (Stock)session.get(Stock.class, 114); 
Set sets = stock.getStockDailyRecords();
        
for ( Iterator iter = sets.iterator();iter.hasNext(); ) { 
      StockDailyRecord sdr = (StockDailyRecord) iter.next();
      System.out.println(sdr.getDailyRecordId());
      System.out.println(sdr.getDate());
}

您的预期结果是什么,这是从集合中每次提取10条记录? 查看输出
输出量

Hibernate: 
    select ...from mkyong.stock
    where stock0_.STOCK_ID=?

Hibernate: 
    select ...from mkyong.stock_daily_record
    where stockdaily0_.STOCK_ID=?

批量大小在这里什么也没做,不是批量大小的工作方式。 请参阅此语句。

批量大小提取策略未定义在集合中装入多少记录。 相反,它定义了应加载的集合数量。

-重复N次,直到您记住该声明-

另一个例子

让我们看另一个示例,您想要一张一张地打印所有库存记录及其相关的库存每日记录(集合)。

List<Stock> list = session.createQuery("from Stock").list();

for(Stock stock : list){
        	
    Set sets = stock.getStockDailyRecords();
            
    for ( Iterator iter = sets.iterator();iter.hasNext(); ) { 
            StockDailyRecord sdr = (StockDailyRecord) iter.next();
            System.out.println(sdr.getDailyRecordId());
            System.out.println(sdr.getDate());
    }
}
没有批量提取策略

输出量

Hibernate: 
    select ...
    from mkyong.stock stock0_

Hibernate: 
    select ...
    from mkyong.stock_daily_record stockdaily0_ 
    where stockdaily0_.STOCK_ID=?

Hibernate: 
    select ...
    from mkyong.stock_daily_record stockdaily0_ 
    where stockdaily0_.STOCK_ID=?

Keep repeat the select statements....depend how many stock records in your table.

如果数据库中有20条股票记录,则Hibernate的默认获取策略将生成20 + 1条select语句并命中数据库。

1.选择语句以检索所有库存记录。
2.选择与其相关的收藏
3.选择与其相关的收藏
4.选择与其相关的收藏
…。
21.选择与其相关的收藏

生成的查询效率不高,并导致严重的性能问题。

启用了batch-size = '10'的提取策略

让我们看另一个启用batch-size = '10'的示例。
输出量

Hibernate: 
    select ...
    from mkyong.stock stock0_

Hibernate: 
    select ...
    from mkyong.stock_daily_record stockdaily0_ 
    where
        stockdaily0_.STOCK_ID in (
            ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
        )

现在,Hibernate将使用select * in *语句来预取集合。 如果您有20条库存记录,它将生成3条选择语句。

1.选择语句以检索所有库存记录。
2.选择In语句以获取其相关集合(一次10个集合)
3.选择In语句以获取其相关集合(一次为下10个集合)

启用批处理大小后,它将select语句从21个select语句简化为3个select语句。

4. fetch =“ subselect”或@Fetch(FetchMode.SUBSELECT)

此提取策略可在子select语句中启用其所有相关集合。 让我们再次看到相同的查询。

List<Stock> list = session.createQuery("from Stock").list();

for(Stock stock : list){
        	
    Set sets = stock.getStockDailyRecords();
            
    for ( Iterator iter = sets.iterator();iter.hasNext(); ) { 
            StockDailyRecord sdr = (StockDailyRecord) iter.next();
            System.out.println(sdr.getDailyRecordId());
            System.out.println(sdr.getDate());
    }
}

输出量

Hibernate: 
    select ...
    from mkyong.stock stock0_

Hibernate: 
    select ...
    from
        mkyong.stock_daily_record stockdaily0_ 
    where
        stockdaily0_.STOCK_ID in (
            select
                stock0_.STOCK_ID 
            from
                mkyong.stock stock0_
        )

启用“ subselect”后,它将创建两个select语句。

1.选择语句以检索所有库存记录。
2.在子选择查询中选择其所有相关集合。

结论

提取策略具有高度的灵活性,并且是优化Hibernate查询的非常重要的调整,但是如果在错误的位置使用它,将是完全的灾难。

参考

1. http://docs.jboss.org/hibernate/core/3.3/reference/en/html/performance.html
2. https://www.hibernate.org/315.html

翻译自: https://mkyong.com/hibernate/hibernate-fetching-strategies-examples/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值