关于Hibernate一对一不能延迟加载的总结
2012-10-11 19:04
357 查看
转载于:http://www.blogjava.net/wangxinsh55/archive/2011/11/09/363353.html
众所周知,到了Hibernate3.0以后,关联关系的对象默认都是使用延迟加载,例 如<one-to-many>时.但我在映射<one-to-one>,<many-to-one>关系时指定了 lazy="true",但是在查询对象时,我只想查询一个对象,仍然会把这个对象所关联的<one-to-one>,<many- to-one>对象一起查询出来,这样造成了极大的性能浪费.在不指定lazy属性时,<many-to-one>所关联的对象反而会
延迟加载,这让我大为困惑,还以为是Hibernate的bug.
在网上查找资料,说在为了延迟加载<one-to-one>,<many-to-one>所关联的对象,需要设置被关联的对象<class name="" lazy="true">,我也这样做了,但是仍然没有效果.
仔 细阅读了Hibernate的手册,才发现原来要延迟加载<one-to-one>,<many-to-one>所关联的对象 时,除了要指定lazy="true"外,还需要运行期字节码增强,而我省去了这一步,所以延迟加载没有效果.同时还发现在默认情况下,<one- to-one>,<many-to-one>的lazy属性是"proxy"而不是"true"!因此如果直接采用lazy的默认值, 是可以延迟加载的.
总结一下:
<many-to-one>默认的属性是lazy="proxy",此时默认是会延迟加载的.在指定了lazy="true"之后,必须要经过运行期字节码增加,延迟加载才有效果.
而<one- to-one>相对要复杂一点,延迟加载还要受到constrained属性的限制.constrained="false"时表明实体和被关联到 的实体的约束不是强制的,即存在一个实体时,它通过<one-to-one>关联的实体可能存在,也可能不存在,这时在查询实体 时,Hibernate总会发起一次查询检查<one-to-one>所关联的实体是否存在,而这时已经可以把one-to-one关联的实 体查询出来了,因此在<one-to-one>关系中,如果constrained="false",总是会立即加载关联到的实体.
如果当constrained="true",且lazy="proxy"(默认),是可以延迟加载的.
如果当constrained="true",且lazy="true"时,需要经过运行期字节码增加,延迟加载才会奏效.
但是这里我还是有个疑问,既然在lazy="proxy"时,已经实现了延迟加载的效果,为什么在lazy="true"时,还需要动态字节码增强才能实现延迟加载呢?
Re: Hibernate中的延迟加载
以后在one-to-one或many-to-one中不会再有lazy="true"了,你可以理解成no-proxy.
[1]起码还是好的方向: 默认就可以lazy了. 而且来了extra :)
[2]写Hibernate的哥们也是要活命的嘛, 不改变怎么来的咨询费, 不过Hibernate的migration写的也还不错.
[3]constrained如你所说, 而且我估计这个属性以后不会有太大变更.
字节码增强是一种基于你的配置和定义,在运行时修改代码的技术。有一个通用的代码创建库cglib,它允许延迟加载一个实现类,从而避免创建一 个需要延迟 加载的类型。Spring,iBatais,Hibernate这些框架都使用了这种技术,即所谓的动态代理。动态代理有两种方式:
1)如果需要代理的类实现了一个接口,那么这些框架就在运行时使用reflect反射机制来创建一个实现了此接口的类作为代理类。
2)如果这个类没有实现任何接口,那么就会使用cglib库提供的方法来动态创建一个此类的子类作为代理类。其实也是使用了反射机制。cglib就是处理第二种情况的一个通用框架。
方法是:在主控方的<one-to-one>上加constrained=true,在被控方的class上加lazy=true,其实这个方法是可以的
我们都知道,一对一有两种实现方式,主键关联和外键关联
主键关联:就是说两个表的主键是一样的
product(id,name) image(id,name)
其中image的id引用product的id,product是主,image是次
外键关联:就是说是通过一个字段引用另一个表的主键
product(id,name) image(id,name,productid)
其中image的productid引用product的id,product是主,image是次
在主键关联时,按如下进行实体映射,是可以实现延迟加载的
<hibernate-mapping package="onetoonebypk">
<class name="Product1" table="product1">
<id name="id" unsaved-value="null">
<column name="id"></column>
<generator class="uuid.hex"></generator>
</id>
<property name="name" column="name"></property>
<one-to-one name="image1"
class="Image1"
cascade="all"
constrained="true"
>
</one-to-one>
</class>
</hibernate-mapping>
<hibernate-mapping package="onetoonebypk" >
<class name="Image1" table="image1" lazy="true">
<id name="id">
<generator class="foreign">
<param name="property">product1</param>
</generator>
</id>
<property name="name" column="name"></property>
<one-to-one name="product1"
class="Product1"
cascade="all">
</one-to-one>
</class>
</hibernate-mapping>
当使用外键关联是,如果按如下方式编写映射文件,使不能进行延迟加载的
<hibernate-mapping package="onetoonebyfk" >
<class name="Image" table="image" lazy="true">
<id name="id">
<generator class="uuid.hex"/>
</id>
<property name="name" column="name"></property>
<many-to-one name="product"
class="Product"
unique="true"
column="productid">
</many-to-one>
</class>
</hibernate-mapping>
<hibernate-mapping package="onetoonebyfk">
<class name="Product" table="product">
<id name="id" unsaved-value="null">
<column name="id"></column>
<generator class="uuid.hex"></generator>
</id>
<property name="name" column="name"></property>
<one-to-one name="image"
class="Image"
cascade="all"
constrained="true"
property-ref="product"
>
</one-to-one>
</class>
</hibernate-mapping>
为什么呢,我认为是在主方product中,有这样一句话property-ref="product"
这句话的意思是说加外键关联类的属性,如果不指定这个属性,关联类的主键就会被使用
也就是说,如果不制定这个,在查找image时就会使用
select * from image where imageid==product_id 而不是
select * from image where productid==product_id
我们在知道product_id的时候,需要找image中productid等于product_id记录,而不是用image的主键作为比较
去掉propery-def后,倒是可以延迟加载,但在读取product.getImage()方法时会报没有指定id记录的异常,不过这也正常,我们怎么能用image的主键和product_id建立查询条件呢
至于为什么这样,我不是很清楚
总之:我目前的结论是:用主键关联,可以延迟加载,用外键关联,暂时不考虑延迟加载
至于为什么,希望能到大家的帮助
众所周知,到了Hibernate3.0以后,关联关系的对象默认都是使用延迟加载,例 如<one-to-many>时.但我在映射<one-to-one>,<many-to-one>关系时指定了 lazy="true",但是在查询对象时,我只想查询一个对象,仍然会把这个对象所关联的<one-to-one>,<many- to-one>对象一起查询出来,这样造成了极大的性能浪费.在不指定lazy属性时,<many-to-one>所关联的对象反而会
延迟加载,这让我大为困惑,还以为是Hibernate的bug.
在网上查找资料,说在为了延迟加载<one-to-one>,<many-to-one>所关联的对象,需要设置被关联的对象<class name="" lazy="true">,我也这样做了,但是仍然没有效果.
仔 细阅读了Hibernate的手册,才发现原来要延迟加载<one-to-one>,<many-to-one>所关联的对象 时,除了要指定lazy="true"外,还需要运行期字节码增强,而我省去了这一步,所以延迟加载没有效果.同时还发现在默认情况下,<one- to-one>,<many-to-one>的lazy属性是"proxy"而不是"true"!因此如果直接采用lazy的默认值, 是可以延迟加载的.
总结一下:
<many-to-one>默认的属性是lazy="proxy",此时默认是会延迟加载的.在指定了lazy="true"之后,必须要经过运行期字节码增加,延迟加载才有效果.
而<one- to-one>相对要复杂一点,延迟加载还要受到constrained属性的限制.constrained="false"时表明实体和被关联到 的实体的约束不是强制的,即存在一个实体时,它通过<one-to-one>关联的实体可能存在,也可能不存在,这时在查询实体 时,Hibernate总会发起一次查询检查<one-to-one>所关联的实体是否存在,而这时已经可以把one-to-one关联的实 体查询出来了,因此在<one-to-one>关系中,如果constrained="false",总是会立即加载关联到的实体.
如果当constrained="true",且lazy="proxy"(默认),是可以延迟加载的.
如果当constrained="true",且lazy="true"时,需要经过运行期字节码增加,延迟加载才会奏效.
但是这里我还是有个疑问,既然在lazy="proxy"时,已经实现了延迟加载的效果,为什么在lazy="true"时,还需要动态字节码增强才能实现延迟加载呢?
Re: Hibernate中的延迟加载
以后在one-to-one或many-to-one中不会再有lazy="true"了,你可以理解成no-proxy.
[1]起码还是好的方向: 默认就可以lazy了. 而且来了extra :)
[2]写Hibernate的哥们也是要活命的嘛, 不改变怎么来的咨询费, 不过Hibernate的migration写的也还不错.
[3]constrained如你所说, 而且我估计这个属性以后不会有太大变更.
字节码增强是一种基于你的配置和定义,在运行时修改代码的技术。有一个通用的代码创建库cglib,它允许延迟加载一个实现类,从而避免创建一 个需要延迟 加载的类型。Spring,iBatais,Hibernate这些框架都使用了这种技术,即所谓的动态代理。动态代理有两种方式:
1)如果需要代理的类实现了一个接口,那么这些框架就在运行时使用reflect反射机制来创建一个实现了此接口的类作为代理类。
2)如果这个类没有实现任何接口,那么就会使用cglib库提供的方法来动态创建一个此类的子类作为代理类。其实也是使用了反射机制。cglib就是处理第二种情况的一个通用框架。
方法是:在主控方的<one-to-one>上加constrained=true,在被控方的class上加lazy=true,其实这个方法是可以的
我们都知道,一对一有两种实现方式,主键关联和外键关联
主键关联:就是说两个表的主键是一样的
product(id,name) image(id,name)
其中image的id引用product的id,product是主,image是次
外键关联:就是说是通过一个字段引用另一个表的主键
product(id,name) image(id,name,productid)
其中image的productid引用product的id,product是主,image是次
在主键关联时,按如下进行实体映射,是可以实现延迟加载的
<hibernate-mapping package="onetoonebypk">
<class name="Product1" table="product1">
<id name="id" unsaved-value="null">
<column name="id"></column>
<generator class="uuid.hex"></generator>
</id>
<property name="name" column="name"></property>
<one-to-one name="image1"
class="Image1"
cascade="all"
constrained="true"
>
</one-to-one>
</class>
</hibernate-mapping>
<hibernate-mapping package="onetoonebypk" >
<class name="Image1" table="image1" lazy="true">
<id name="id">
<generator class="foreign">
<param name="property">product1</param>
</generator>
</id>
<property name="name" column="name"></property>
<one-to-one name="product1"
class="Product1"
cascade="all">
</one-to-one>
</class>
</hibernate-mapping>
当使用外键关联是,如果按如下方式编写映射文件,使不能进行延迟加载的
<hibernate-mapping package="onetoonebyfk" >
<class name="Image" table="image" lazy="true">
<id name="id">
<generator class="uuid.hex"/>
</id>
<property name="name" column="name"></property>
<many-to-one name="product"
class="Product"
unique="true"
column="productid">
</many-to-one>
</class>
</hibernate-mapping>
<hibernate-mapping package="onetoonebyfk">
<class name="Product" table="product">
<id name="id" unsaved-value="null">
<column name="id"></column>
<generator class="uuid.hex"></generator>
</id>
<property name="name" column="name"></property>
<one-to-one name="image"
class="Image"
cascade="all"
constrained="true"
property-ref="product"
>
</one-to-one>
</class>
</hibernate-mapping>
为什么呢,我认为是在主方product中,有这样一句话property-ref="product"
这句话的意思是说加外键关联类的属性,如果不指定这个属性,关联类的主键就会被使用
也就是说,如果不制定这个,在查找image时就会使用
select * from image where imageid==product_id 而不是
select * from image where productid==product_id
我们在知道product_id的时候,需要找image中productid等于product_id记录,而不是用image的主键作为比较
去掉propery-def后,倒是可以延迟加载,但在读取product.getImage()方法时会报没有指定id记录的异常,不过这也正常,我们怎么能用image的主键和product_id建立查询条件呢
至于为什么这样,我不是很清楚
总之:我目前的结论是:用主键关联,可以延迟加载,用外键关联,暂时不考虑延迟加载
至于为什么,希望能到大家的帮助
相关文章推荐
- 转:关于Hibernate一对一不能延迟加载的总结
- 关于Hibernate一对一不能延迟加载的总结
- 关于Hibernate一对一延迟加载的总结
- Hibernate延迟加载小小总结
- 关于延迟加载(lazy)和强制加载(Hibernate.initialize(Object proxy) )
- 关于Hibernate延迟加载
- 主题:关于hibernate延迟加载的错误解决方案
- 关于延迟加载(lazy)和强制加载(Hibernate.initialize(Object proxy) )
- 关于Hibernate中延迟加载错误的处理方案
- 一些关于Hibernate延迟加载的误区
- 关于hibernate中的load,get,以及延迟加载问题
- 项目总结--maven+springsecurity+solr+springmvc+hibernate 延迟加载处理+hibernate sql对象处理(sql执行插入)+spring注解方式+邮件 + JNDI+项目框架写法+jasperreprot的简单应用
- Hibernate懒加载/延迟加载机制总结
- Hibernate 关于 Lazy延迟加载的解释说明
- 关于延迟加载(lazy)和强制加载(Hibernate.initialize(Object proxy) )
- 关于延迟加载(lazy)和强制加载(Hibernate.initialize(Object proxy) )
- Hibernate: 关于延迟加载(lazy)和强制加载 : Hibernate.initialize()
- Hibernate懒加载/延迟加载机制总结
- 关于延迟加载(lazy)和强制加载(Hibernate.initialize(Object proxy) )
- [转]PO和VO、关于延迟加载(lazy)和强制加载(Hibernate.initialize(Object proxy) )