Hibernate中OneToOne延时加载的问题-现象和原因

在Hibernate中,OneToOne的延迟加载可能导致N+1 Select问题,尤其是在双向关联时。虽然在Owner端查询能正常延迟加载,但通过关联实体查询时,即使指定fetch = FetchType.LAZY,仍会触发额外的查询。原因是Car表没有关系字段,Hibernate需要通过查询确认关联关系。此外,延迟加载原理中,代理对象只能对非null映射对象建立,为null则不能实现延迟加载,因此需要查询判断。
摘要由CSDN通过智能技术生成

关于OneToOne的延迟加载(fetch = FetchType.LAZY),我觉得是非常需要注意的一个问题。它不只是存在于Hibernate中,其他的ORM persistence framekwork也有同样的问题,至少我用过的eclipseLink也是一样的。这个问题之所以重要,是因为它在背后偷偷的降低了查询数据库的效率,但又极难发现,特别是当你进入一个老项目,发现软件的运行效率极低时,你就应该检查一下已有代码中是否合理定义了OneToOne的关联。

N+1 Select

我们先简单的回顾一下ORM里面常见的N+1 Select的问题:
Java Persistence with Hibernate的13章有比较清楚的解释,这里举个简单的例子:
假设我们在数据库里定义了Car这种数据类型,每辆Car都关联了Wheel的Object。简单的就是Car和Wheel之间是一种OneToMany的关联。
如果我们需要从数据库里面取出所有的cars。那么典型的ORM框架会做如下的步骤:
首先,取出所有的Cars:

SELECT * FROM Cars;

然后针对每一辆Car:

SELECT * FROM Wheel WHERE CarId = ?

换句话说,ORM用了一条select语句来取出所有的Car,然后用了额外的N条select语句来取出和Car相关联的对象,这是相当损耗效率的一种行为。哪怕我们自己写一条:

SELECT * FROM Wheel

将select的执行次数由N+1变为2,然后在内存中自己查找car和wheel,也比执行N+1要强很多。
特别是有的时候,当我们在查询Car的时候,未必需要用到Wheel的数据,这时更是一种额外的开销。

延迟加载

所以,ORM框架为我们提供了一种机制,延迟加载,只有确定要使用关联对象的时候我们才把它从数据库里面读取出来。Hibernate 的延迟加载本质上就是代理模式的应用,当程序通过 Hibernate 装载一个实体时,默认情况下,Hibernate 并不会立即抓取它的集合属性、关联实体所以对应的记录,而是通过生成一个代理来表示这些集合属性、关联实体,这就是代理模式应用带来的优势。
而这里要讨论的OneToOne就是上面所提到的关联实体。

OneToOne无法延迟加载

那OneToOne的延迟加载有什么问题呢?
我们先来简单创建两个Entity(Car和SteelingWheel),并在两个Entity之间创建1对1的关联。
Car:

@Entity
@Table( name = "car" )
public class Car
{
   
    @Id
    @Column( name = "id" )
    @GeneratedValue( strategy = GenerationType.AUTO )
    Long id;

    @Column( name = "brand" )
    String brand;

    /*关联SteelingWheel,同时指定延迟加载,当然hibernate是默对关联实体进行延迟加载的*/
    @OneToOne( cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "car" )
    
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值