Hibernate实体关系映射

来源:互联网 发布:centos的vmdk文件下载 编辑:程序博客网 时间:2024/05/01 03:47

概要

数据库中的表是有关系的,两个表之间可以通过外键关联。
关系有:一对一、一对多、多对一、多对多等。
要使Hibernate正确处理这些关系,需要正确的配置。

常用注解

@OneToMany
@OneToOne
@ManyToOne
@ManyToMany

名词解释

  • 什么是单边?双边?
    单边指一边有另一边对象引用,一边没有。
    双边指双边都有对方对象的引用。

单边OneToMany例子

以“用户”和“Email”为例,一个用户可以拥有多个电子邮箱

tb_person(用户表):id、name
tb_email(Email表):id、email、person_id(外键,参考用户表的id)

@OneToMany(fetch=FetchType.EAGER,targetEntity=Email.class,cascade={CascadeType.PERSIST,Cascade.REMOVE,Cascade.MERGE,Cascade.REFRESH})//相当于Cascade.ALL设置级联关系,上面分别表示:保存、删除、修改、刷新时@JoinColumns(Value={@JoinColumn(name="person_id",referencedColumnName="id")})@OrderBy(value="email desc")private List<Email> emails=new ArrayList<Email>();//外键

延迟加载和即时加载

fetch=FetchType.LAZY / FetchType.EAGER
例如上面的“人”这个实体,设置对Email是即时加载的话,在加载Person的时候就会加载Email,而使用延迟加载在调用Email的get方法时才会去加载

一般来说延迟加载比即时加载节省资源,尤其是关联的表数量较多的时候,但是使用延迟加载,假如在调用email的get方法之前已经关闭了session,会导致加载email异常。

单边ManyToOne例子

以“博文”和“类型”为例

tb_blog(博文表):id、content(longtext类型)、type_id(外键,参考类型表的id)

tb_type(类型表):id、name(unique)

@ManyToOne(cascade={CascadeType.PERSIST},fetch=FetchType.EAGER)@JoinColumn(name="type_id")Private Type type;

双边的OneToMany和ManyToOne例子

以“班级”和“学生”为例

tb_class(班级表):id、name、
tb_student(学生):id、name、sex、class_id(外键)

在双边关系中,控制权一般交给多方,因此下面使用反向配置。假如像之前的单边一对多关系配置,则控制权在一方

Clazz.java实体的配置

@OneToMany(mappedBy="clazz")//反向配置,告诉Hibernate,配置信息在Student类的clazz属性找private List<Student> students=new ArrayList<Student>();

Student.java实体配置

@ManyToOne(fetch=FetchType.EAGER,cascade={Cascade.PERSIST})@JoinColumn(name="class_id")private Clazz clazz;

单边ManyToMany例子

多对多关系至少需要三张表,两个表用来保存实体类,另一张表保存两个实体的关系
这里以“博文”和“标签”为例

tb_blog(博文表):id、name、content
tb_tag(标签表):id、name
tb_blog_tag(关系表):b_id、t_id

Blog.java配置

@ManyToMany(fetch=FetchType.EAGER,cascade={CASCADE.PERSIST})@JoinTable(    name="tb_blog_tag",    joinColumns=@JoinColumn(name="b_id",referenceColumnName="id"),    inversJoinColumns=@JoinColumn("t_id",referenceColumnName="id"))private Set<Tag> tags=new HashSet<Tag>();

使JoinTable来指定中间表
joinColumns指定该表(例子中为blog表)与中间表的关系
inverJoinColumns指定另一张表(例子中为tag表)与中间表的关系

双边ManyToMany例子

在上面单边ManyToMany例子基础上,对Tag实体增加ManyToMany配置

Tag.java

@ManyToMany(mappedBy="tags") //反向配置private Set<Blog> blogs=new Set<Blog>();

单边OneToOne例子

以”飞机”和”机务人员”为例
一个机长只对应一辆飞机

tb_plane(飞机表):id、name、captain_id
tb_crew(机务人员表):id、name、plane_id

Plane.java

@OneToOne(cascade={CascadeType.PERSIST,CascadeType.REFRESH})@JoinColumn(name="captain_id",unique=true)private Crew captain;@OneToMany(mappedBy="plane",cascade=CascadeType.PERSIST)private Set<Crew> crews=new HashSet<Crew>();

Crew.java

@ManyToOne(cascade=CascadeType.PERSIST)@JoinColumn(name="plane_id")private Plane plane;

双边OneToOne例子

在上面单边OneToOne的基础上,修改Sailor.java

增加

@OneToOne(mappedBy="captain")private Ship captainedShip;

主键相同的OneToOne例子

以“客户”和“客户唯一地址”为例
客户和地址使用相同的主键

tb_customer(客户表):id、name
tb_address(地址表):id、address

Customer.java

@Id@GeneratedValue(stratety=GenerationType.AUTO)private Integer id;//...@OneToOne@PrimaryKeyJoinColumnprivate Address address;

Address.java

@Idprivate Integer id;//不能使用自增长Id@OneToOne@PrimaryKeyJoinColumnprivate Customer customer;

要注意的一些点

  • 使用XML配置文件来配置实体间的关系功能要多得多
  • XML可以使用String等基本类型来作为实体,而注解方式,实体必须为一个POJO。
  • 一对多关系中,常常将主动权给多方,一方常常使用反向配置
  • referencedColumnName默认是表的主键,如果为主键可省去
  • 在List<>,Set<>等泛型中指定了类名,可以在关系注解中省略targetEntity属性
0 0
原创粉丝点击