为什么hibernate会返回代理对象?

时间:2010-04-07 18:12:50

标签: java hibernate spring

我有一个调用DAO的服务方法,然后DAO从数据库返回一个对象。从系统的许多部分调用此方法。但是,一种特殊方法是获取返回类型的ObjectClass _ $$ _ javassist_somenumber作为类型。哪个是扔东西。我调用的服务方法与其他地方完全相同,那么为什么hibernate会返回代理而不是自然对象呢?

我知道有办法公开“代理”对象,但我觉得我不应该这样做。

查询只是

hibernateTemplate.find("from User u where u.username = ?", username)

我正在使用hibernate 3.3 btw。

3 个答案:

答案 0 :(得分:9)

它是一个代理对象,以支持延迟加载;基本上,只要通过访问器/ getter方法引用子对象或查找对象,如果链接实体不在会话高速缓存中,则代理代码将转到数据库并加载链接对象。它使用javassist来有效地动态生成对象的子类实现(尽管我认为它也可以配置为使用CGLIB)。

如果它没有以这种方式代理,那么实现无缝延迟加载几乎是不可能的。

我不记得我的头顶是否使用预先加载,然后是否会返回自然物体。我通常不建议使用急切加载,尤其是如果你有很多链接子实体,因为它很快就会成为一个巨大的性能瓶颈,因为它会将每个链接对象吸入内存。

此外,如果您需要区分类类型,而不是使用obj.getClass(),请使用Hibernate.getClass(obj),这将返回自然对象类,无论它是否被代理:请参阅Hibernate API Javadocs here

答案 1 :(得分:2)

如果并非所有成员都已解析,则Hibernate会返回代理,即对象未完成。这通常是提高性能所需的功能,并且(我认为)是hibernate中的默认设置。

如果您不想要代理,可以在hbm.xml文件中禁止延迟加载,即使用预先加载。请查看hibernate文档以获取确切的语法。

使用代理对象永远不会直接访问成员,只能通过getter访问,即使在成员函数中也是如此。当你得到它时,Hibernate魔法会填充成员。这样您就不必暴露对象。也不要在潜在的代理对象上使用instanceof。但无论如何这都是代码味道。

答案 2 :(得分:1)

在我看来这个表达:

hibernateTemplate.find("from User u where u.username = ?", username)

应该始终返回POJO,而不是代理。这是因为标准HQL /条件返回非代理对象,而是原始实体类的对象。这与懒惰关联抓取:

不同
@Entity
class X {
    @ManyToOne(fetch = FetchType.LAZY)
    private User user;
}

在此处从db获取X对象,我们将在X.user字段(代理User实例)中设置一个惰性代理。

现在,有时候你做from User where [...]你有POJO,有时候有代理对象。通常这是因为在某些执行中User首先通过关联从db中获取对象(from X where [...]在给定的hibernate会话中首先调用查询)。已经(代理)User实例,即使对于from User where [...]这样的普通查询,hibernate也会重用此实例。