2010-04-07 151 views
4

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

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

查询仅仅是

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

我使用Hibernate 3.3 BTW。

回答

9

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

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

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

另外,如果你需要在类的类型区分,而不是使用obj.getClass(),使用Hibernate.getClass(obj)它会给你回自然的对象类,无论它是proxed与否:请参阅Hibernate API的Javadoc here

+0

那么对象是急切加载,因为我得到一个代理对象这个特别的电话,我想你不能保证该对象会是。有趣的是,当我从方法A调用DAO.getUser(String username)时,我得到User对象,但从方法B调用完全相同的庄园中的方法,我得到代理。 – predhme 2010-04-07 19:10:34

+1

通常,问题是以这种方式返回的代理*未被正确初始化;否则,如果它被正确填充,事情应该已经正常进行。任何人都知道为什么find方法可能会返回未初始化的代理? – 2011-07-22 03:15:57

2

如果不是所有成员都解析完成,Hibernate将返回代理,即对象不完整。这通常是提高性能的一个理想功能,并且(我认为)是hibernate的默认设置。

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

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

+2

Instanceof检查仍然有效,因为代理仍然是您班级的子类的实例。不起作用的是类对象的等号或身份比较(由getClass()提供)。 – whiskeysierra 2010-04-07 23:28:59

+0

我遇到了这个问题,但发现上面的说法是不正确的,这是我们如何发现问题。我们迭代一个集合并检查'instanceof'是否失败的预期对象。我真的不知道java是如何处理这个内部的,但是我们在println中加入了“instanceof x =”+(obj instanceof x)并且它打印为false。 Hibernate.getClass(obj)很好,但我想深入了解对象未完全初始化的原因。 – mikemil 2013-10-10 15:50:53

+0

@whiskeysierra - 抱歉,忘记了包含您的ID以通知上述评论。 – mikemil 2013-10-10 15:58:15

0

在我看来这表达:

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

应该总是返回POJO,而不是一个代理。这是因为标准HQL /标准返回非代理对象,而是返回原始实体类的对象。这是懒协会取不同:

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

获取X对象从这里分贝,我们将在X.user字段(代理User实例)一个懒惰的代理。

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

相关问题