hibernate注解(三)
来源:互联网 发布:电子书包软件 编辑:程序博客网 时间:2024/05/16 08:42
我们继续介绍hibernate注解的相关内容
1. OneToOne懒加载问题
一对一注解时,若采用外键列进行实体的关联的话,懒加载问题是需要注意下的。如下:
Student表:
id int not nullname varchar(50) not nullcard_id int not null
Card表:
id int not nullcard_no varchar() not null
Student类
public class Student {private int id;private String name;private Card card;....@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)@JoinColumn(name = "card_id")public Card getCard() {return card;}public void setCard(Card card) {this.card = card;}}
Card类
public class Card {private int id;private String cardNo;private Student student;....@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "card")public Student getStudent() {return student;}public void setStudent(Student student) {this.student = student;}}
按照上述关系,运行代码后我们会发现,Student获取Card时可以懒加载,但Card获取Student时却无法懒加载,那么这是为什么呢?
原因:在Card表里由于没有关系字段,因此仅从Card表角度看无法知道拥有该卡的学生是谁(除非在Card表建立Student表的外键student_id,但由于冗余了关系字段,因此很少有人这么干吧【注意sql的join语句是考虑了两张表的】),而从Student角度不一样,由于含有card_id字段可能清楚知道该学生拥有一张卡。
正是由于上面的原因,因此当从Card获取Student时,hibernate为了确定Student表中到底有没有该Card,因此发了一条sql:select * from Student where card_id = ?,参数既是该Card的id,以此来维护Card与Student的关系。
还有一种解释,但需要理解hibernate的懒加载的机制:代理。
2. 懒加载原理
hibernate使用了代理(Proxy),对实体的调用会被代理接受和处理,hibernate可以设置这个代理被调用到的时候去加载数据,从而实现延迟加载。那么对于一个映射对象,要么它有值,要么它是null,对于null值建立代理是没多大作用的,而且也不能对null建立动态代理。那就是说hibernate在对延迟加载建立代理的时候要考虑这个映射的对象是否是null。如果是null不需要建立代理,直接把映射的值设置成null,如果映射的对象不为null,那么hibernate就建立代理对象。
简而言之,为null就不能懒加载,为代理对象才能懒加载。
那么解决上述问题的办法呢?
● Card类的getStudent改为manyToOne,并设置unique=true。缺点:需要将字段改为Set<Student>。
● 手动为Student建立代理对象。(不建议这么做,而且我也没试过)
● 采用no-proxy懒加载机制,对类用instrument进行增强,即用类增强器对二进制Class文件进行强化处理。(很少有人这么做,不推荐)
以下是利用ant调用hibernate类增强器对class文件进行强化处理,ant的build.xml脚本如下:
<?xml version="1.0" encoding="UTF-8"?><project name="hibernatelazy" default="instrument" basedir="."> <property name="lib.dir" value="./lib"/> <property name="classes.dir" value="./classes"/> <path id="lib.class.path"> <fileset dir="${lib.dir}"> <include name="**/*.jar"/> </fileset> </path> <target name="instrument"> <taskdef name="instrument" classname="org.hibernate.tool.instrument.InstrumentTask"> <classpath path="${classes.dir}"/> <classpath refid="lib.class.path"/> </taskdef> <instrument verbose="true"> <fileset dir="${classes.dir}/com/derek/known/hbm"> <include name="Knownquestions.class"/> </fileset> </instrument> </target></project>
其中注意:
<property name="lib.dir" value="./lib"/>所需的JAR文件路径。
<property name="classes.dir" value="./classes"/>编译输出路径。
我把build.xml放在了WEB-INF目录下,输出路径就设置为该目录下的classes目录,待增强的字节码文件为classes目录下的com/derek/known/hbm/Knownquestions.class; 在命令行下切换到此目录,执行ant命令,即生成新的Knownquestions.class。
● 放弃懒加载,改为join的加载策略,或者使用hql:from Card t inner join fetch t.student r
3. 懒加载注解方式详解
● FetchType(@OneToOne、@OneToMany等注解里的fetch属性对应的类,本身没有注解)
JPA标准的通用加载策略注解属性。FetchType可选值意义与区别如下:
FetchType.LAZY:懒加载,在第一次访问关联对象的时候加载
FetchType.EAGER:立刻加载,在查询主对象的时候同时加载关联对象。
● @Fetch
hibernate定义了加载关联关系的获取策略。Fetch可选值意义与区别如下:
FetchMode.JOIN:始终立刻加载,使用外连(outer join)查询的同时加载关联对象,忽略FetchType.LAZY设定。
FetchMode.SELECT:支持懒加载(除非设定关联属性lazy=false),当访问每一个关联对象时加载该对象,会累计产生N+1条sql语句
FetchMode.SUBSELECT:支持懒加载(除非设定关联属性lazy=false),在访问第一个关联对象时加载所有的关联对象。会累计产生两条sql语句。
● @LazyToOne
hibernate定义了@ManyToOne 和@OneToOne 关联的延迟选项。LazyToOne可选值意义与区别如下:
LazyToOneOption.PROXY:基于代理的延迟加载。
LazyToOneOption.NO_PROXY:基于字节码增强的延迟加载 - 注意需要在构建期处理字节码增强。
LazyToOneOption.FALSE:非延迟加载的关联。
● @LazyCollection
hibernate定义了@ManyToMany和@OneToMany 关联的延迟选项。LazyCollection可选值意义与区别如下:
LazyCollectionOption.TRUE:集合具有延迟性,只有在访问的时候才加载。
LazyCollectionOption.EXTRA:集合具有延迟性,并且所有的操作都会尽量避免加载集合, 对于一个巨大的集合特别有用,因为这样的集合中的元素没有必要全部加载。
LazyCollectionOption.FALSE:非延迟加载的关联。
延迟和获取选项的等效注解
Annotations
Lazy
Fetch
@[One|Many]ToOne](fetch=FetchType.LAZY)
@LazyToOne(PROXY)
@Fetch(SELECT)
@[One|Many]ToOne](fetch=FetchType.EAGER)
@LazyToOne(FALSE)
@Fetch(JOIN)
@ManyTo[One|Many](fetch=FetchType.LAZY)
@LazyCollection(TRUE)
@Fetch(SELECT)
@ManyTo[One|Many](fetch=FetchType.EAGER)
@LazyCollection(FALSE)
@Fetch(JOIN)
- hibernate注解(三)
- Hibernate,JPA注解(三)
- Hibernate注解方法使用主键生成策略@GeneratedValue(三)
- hibernate注解(一)
- hibernate注解(二)
- hibernate注解(一)
- hibernate注解(二)
- hibernate注解(二)
- hibernate注解(一)
- hibernate注解(二)
- Hibernate注解(一)
- 注解(三)
- maven 项目(三)引申--spring集成hibernate+JPA事务配置(扫描注解)
- hibernate注解之实体属性OneToOne 单双向关联(三)
- Hibernate多对多中间表有多个字段字段的注解配置方式(三)
- SSH:Hibernate框架(Hibernate注解配置)
- Hibernate注解(最基础)
- (Hibernate)JPA注解总结
- 用Android-X86和VirtualBox打造高性能Android开发环境
- 各种bug和教训
- 内存相关代码
- GRE通用路由封装协议学习笔记
- android tools:context详解
- hibernate注解(三)
- 如何去建立Linux企业集群
- PHP根据IP判断地区名信息
- 离开团队,你将什么都不是
- Django学习笔记—获取正确的客户端IP地址
- jquery获得checkbox是否选中的状态
- Fragments For All
- Android 4.0 Launcher2源码分析——Workspace滑动
- Linux 系统的兼容性问题