Hibernate 的 Proxy 陷阱

本文介绍了Hibernate中Proxy的概念及其实现LazyLoading的方式,并探讨了使用Proxy时可能遇到的两个陷阱,包括直接访问成员变量和使用instanceOf进行类型判断。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先,什么是Proxy?这个可以参考一下GoF (著名的软件“四人帮”Gang of Four)提出的《设计模式》。简而言之,就是一个子类,在父类的基础上,实现一点附加功能,而将其他请求全都交给父类去实现,因而从用户角度看子类可以完成全部父类的功能以及子类自己附加的功能,所以可以代替父类使用。

Hibernate 使用 Proxy 实现 Lazy Loading 功能。 比如 Person 类有个成员,也是 Person 类,叫做 boss。如果使用 Lazy Loading,在加载一个 Person 的时候,不会自动加载其 boss 的数据,Hibernate 会自动给 Person 类生成一个 Proxy,将其 boss 的 ID 付给这个 Proxy。只有在访问 boss 的具体数据的时候,这个 Proxy 才会自动调取数据。

一个有趣的现象。如果我们使用图形化调试器(比如 Eclipse)。当我们点开调试器中的 boss 的实例查看其数据的时候,这个 Proxy 就会去调取数据。这可能会使得调试和实际执行的行为不一致。


陷阱1:直接访问成员变量

Proxy 会将函数访问转到其父类的同样函数处理。但是 Proxy 自己是不会持有数据的,其自己的成员变量(比如 boss 的姓名)都是 null。 比如,一个 Person 的 equals 函数可能会这样写:
 @Override
 public boolean equals(Object obj) {
    if (obj == null) {
        return false;
    }
    if (obj == this) {
        return true;
    }
    if (!(obj instanceof Person)) {
        return false;
    }
    return name.equals((Person)obj).name);
  }

上面最后那句话看起来没什么问题,也是常见写法。可是,当被传进来的 obj 可能是个 Proxy 的时候,直接访问 obj 的 name 成员变量就不对了 - 因为这永远是 null。因此,访问另一个 obj 的成员变量时要用 getter / setter。


陷阱2:instanceOf

如果用 instanceOf 判断一个对象是否是 Person 类,那么就没有考虑到 Proxy 的情况。文章给出的建议是关掉 lazy loading,恐怕不是个很好的建议。可以考虑用 Class.isAssignableFrom 吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值