论坛首页 Java企业应用论坛

对robbin所说Hibernate缺陷的一些不理解

浏览 20026 次
该帖已经被评为良好帖
作者 正文
   发表时间:2007-05-25  
看到robbin的文章有些不太明白
http://robbin.iteye.com/blog/81990
引用

Hibernate不够易用,而且有一些明显的缺陷:one-to-one必须通过bytecode enhancement才能lazy loading;不支持多态关联

前半句,对于one-to-one关联,在Gavin King最新的《Java Persistance with Hibernate》中13.1节提到:必须是constrained="true"的关联才可以lazy loading,否则可以通过bytecode instrumentation来进行。那么为什么通过bytecode instrument来lazy loading是不好的呢?
对于后半句,为何说hibernate不支持多态关联?
   发表时间:2007-05-25  
fredzhang 写道
看到robbin的文章有些不太明白
http://robbin.iteye.com/blog/81990
引用

Hibernate不够易用,而且有一些明显的缺陷:one-to-one必须通过bytecode enhancement才能lazy loading;不支持多态关联

前半句,对于one-to-one关联,在Gavin King最新的《Java Persistance with Hibernate》中13.1节提到:必须是constrained="true"的关联才可以lazy loading,否则可以通过bytecode instrumentation来进行。那么为什么通过bytecode instrument来lazy loading是不好的呢?
对于后半句,为何说hibernate不支持多态关联?


constrained="true"限制太大了,byteocode增强你自己试试看能不能成功?和compiler,和JDK版本的关系很大,这种方式是很脆弱的,换个JDK版本部署就完蛋了。

多态关联Hibernate就是不支持阿,要不你写个Hibernate支持多态关联的例子给我看看?
0 请登录后投票
   发表时间:2007-05-25  
冒昧说一句,hibernate对于稍复杂的OO设计,映射起来确有麻烦,主要在多态上支持的不够完美。

简单例子:
04-05年一个项目设计,OperationLog对应的Target可以是多种不同Entity。
在JAVA对象层,有个LogTarget接口,多个实体类实现这个LogTarget:
public interface LogTarget{
    public Set getLogs();
}
在ORM层,当时的hibernate只能在Log的mapping上使用<any>映射,
而LogTarget上的Logs也可以用one-to-many加上wheresql解决。

到目前为止还算完美。

可是一旦实现了LogTarget的Entity出现子类,情况就混乱了。
无论如何配置,在子类的getLogs里面都会出现错误(有超类的log)。

-------------

时间有些长,具体细节都忘掉了,大概情况是这样。
0 请登录后投票
   发表时间:2007-05-25  
Gavin King的《Java Persistance with Hibernate》第7.3.1节不就是在讲多态关联吗?
bytecode增强和proxy都是用cglib实现的吧,那么为什么一种方式比较脆弱而另外一种不呢?前者在hibernate应当是在org.hibernate.bytecode.cglib下,后者应当是org.hibernate.proxy.cglib下,两者有一些区别,一个是用cglib 的 MethodInterceptor callback,另一个是cglib的Dispatcher callback。——如果我源码没看错的话...
0 请登录后投票
   发表时间:2007-05-25  
fredzhang 写道
Gavin King的《Java Persistance with Hibernate》第7.3.1节不就是在讲多态关联吗?
bytecode增强和proxy都是用cglib实现的吧,那么为什么一种方式比较脆弱而另外一种不呢?前者在hibernate应当是在org.hibernate.bytecode.cglib下,后者应当是org.hibernate.proxy.cglib下,两者有一些区别,一个是用cglib 的 MethodInterceptor callback,另一个是cglib的Dispatcher callback。——如果我源码没看错的话...


这是因为one-to-one关联的lazy loading无法使用cglib的动态增强,必须通过静态编译的方式增强。既然要通过静态编译操作字节码,那就和compiler的版本关系很大了。

多态关联关系Hibernate支持的很差,你对比一下RoR的多态关联就知道好的多态关联支持是怎么回事了。
0 请登录后投票
   发表时间:2007-05-25  
原来RoR的多态关联跟Gavin King polymorphic associations的提法还是有不小差别的,从这个角度来说,hibernate的确不支持多态关联。

关于one-to-one关联的lazy loading,在constraint="false"的时候,无法使用cglib,在哪里有提及?我在网上没有搜到,除非得去读读源代码。ps hibernate的源代码,比起spring等其他框架,要复杂好多啊。
0 请登录后投票
   发表时间:2007-05-25  
fredzhang 写道
原来RoR的多态关联跟Gavin King polymorphic associations的提法还是有不小差别的,从这个角度来说,hibernate的确不支持多态关联。

关于one-to-one关联的lazy loading,在constraint="false"的时候,无法使用cglib,在哪里有提及?我在网上没有搜到,除非得去读读源代码。ps hibernate的源代码,比起spring等其他框架,要复杂好多啊。


关于one-to-one关联的从方不能lazy loading是由one-to-one的机制造成的,比如user和contact是一对一,user是主,contact是从,约束依赖于user,那么在数据库中,contact表中应该有一个外键字段指向user表的主键。

当加载contact对象时,从contact表的记录中就可以得到user记录的id,这和多对一是一样的,就可以知道user对象是否存在,不存在则user为null,存在就生成代理对象,所以可以实现主方的延迟加载。

当加载user对象时,从user表记录中没有办法知道这个contact从方是否存在,它就不能确定是用null还是生成代理对象来代替contact对象,因为代理对象一定 != null,所以必须要查询contact表,查询这个从方是否存在。

如果要实现从方的延迟加载,自己写代理,那么这个代理应该加在主方user上,加在从方是没有用的,可以对user类的getContact()方法进行改造,执行该方法时查询contact表,如果记录不存在就返回null。
如果不自己写代理,直接在getContact()方法中采用上面的处理,不知行不行,好像也改变不了hibernate对从方预先加载的动作。


基于上面的情况,所以我现在一般不用one-to-one关联,倒不是一定要延迟加载,还有n+1次问题等等,处理起来比较麻烦,宁可用user到contact的多对一关联,contact为一方,虽然意义上好像反了,但是从user对象可以很方便的得到contact对象,实际上也都是从user来获取contact信息的,延迟加载也没问题。

1 请登录后投票
   发表时间:2007-05-25  
janh说的很对,对user动态增强解决不了这个问题,所以只能静态增强,但是静态增强带来的限制太大。如果把外键保存在user表当中,指向contact,从关联关系上面来说,这是不对的。但是对于Hibernate来说没有办法。

对于RoR来说,不存在这个问题,这是因为ruby是动态语言,可以动态添加代码,所以用RoR的AR进行对象映射,比Hibernate要好用一些。
1 请登录后投票
   发表时间:2007-05-25  
janh 写道


关于one-to-one关联的从方不能lazy loading是由one-to-one的机制造成的,比如user和contact是一对一,user是主,contact是从,约束依赖于user,那么在数据库中,contact表中应该有一个外键字段指向user表的主键。

当加载contact对象时,从contact表的记录中就可以得到user记录的id,这和多对一是一样的,就可以知道user对象是否存在,不存在则user为null,存在就生成代理对象,所以可以实现主方的延迟加载。

当加载user对象时,从user表记录中没有办法知道这个contact从方是否存在,它就不能确定是用null还是生成代理对象来代替contact对象,因为代理对象一定 != null,所以必须要查询contact表,查询这个从方是否存在。

如果要实现从方的延迟加载,自己写代理,那么这个代理应该加在主方user上,加在从方是没有用的,可以对user类的getContact()方法进行改造,执行该方法时查询contact表,如果记录不存在就返回null。
如果不自己写代理,直接在getContact()方法中采用上面的处理,不知行不行,好像也改变不了hibernate对从方预先加载的动作。


基于上面的情况,所以我现在一般不用one-to-one关联,倒不是一定要延迟加载,还有n+1次问题等等,处理起来比较麻烦,宁可用user到contact的多对一关联,contact为一方,虽然意义上好像反了,但是从user对象可以很方便的得到contact对象,实际上也都是从user来获取contact信息的,延迟加载也没问题。



你说的很对,当constrain="false"时,不能用代理。我只是对书上那句话的看法表示疑问,摘抄原句如下:
引用

Does lazy loading of one-to-one associations work? Lazy loading for
one-to-one associations is sometimes confusing for new Hibernate users.
If you consider one-to-one associations based on shared primary keys
(chapter 7, section 7.1.1, “Shared primary key associations”), an association
can be proxied only if it’s constrained="true". For example, an
Address always has a reference to a User. If this association is nullable
and optional, Hibernate first would have to hit the database to find out
whether a proxy or a null should be applied—the purpose of lazy loading
is to not hit the database at all. You can enable lazy loading through
bytecode instrumentation and interception, which we’ll discuss later.

0 请登录后投票
   发表时间:2007-05-27  
为什么不在HIBERNATE中使用 本地SQL?
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics