一、 单项N-1关联
在单项关联和双向关联,都需要在N的一段使用@ManyToOne修饰关联实体的属性。
@ManyToOne支持的属性
属性 |
是否必须 |
说明 |
cascade |
否 |
指定Hibernate对关联实体采样怎样的级联策略 CascadeType.ALL:Hibernate将所有的持久化操作都级联到关联实体 CascadeType.MERGE:Hibernate将merge操作级联到关联实体 CascadeType.PERSIST: Hibernate将persist操作级联到关联实体 CascadeType.REFRESH: Hibernate将refresh操作级联到关联实体 CascadeType.REMOVE: Hibernate将remove操作级联到关联实体 |
fetch |
否 |
指定抓取关联实体时的抓取策略, FetchType.EAGER:立即抓取关联实体,默认 FetchType.LAZY: 延迟抓取关联实体。真正用到关联实体才抓取 |
optional |
否 |
关联关系是否可选 |
targetEntity |
否 |
指定关联实体的类名。默认情况下将通过反射来判断关联实体的类名 使用注意:在@OneToMany、@ManyToMany修饰的1-N、N-N关联中,关联实体的Set集合不带泛型信息,必须指定此属性 |
1. 无连接表的N-1关联
@Entity
@Table(name="address_inf")
public class Address {
@Id @Column(name="address_inf")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int addressId;
}
public class Person {
//标识属性
@Id @Column(name="person_id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
//定义该Person实体关联的Address实体
@ManyToOne(targetEntity=Address.class)
//映射外键列,指定外键列的列名为address_id,不允许为空
@JoinColumn(name="address_id",nullable=false)
@Cascade(CascadeType.ALL)
private Address address;
}
2. 有连接表的N-1关联
使用连接表来映射单项N-1关联,程序需要显式使用@JoinTable注解来映射连接属性
@JoinTable支持的属性
属性 |
是否必须 |
说明 |
name |
否 |
指定链接表表明 |
catalog |
否 |
将连接表放入指定catalog中。没有指定该属性则放入默认catalog中 |
schema |
否 |
将连接表放入指定schema中。没有指定该属性则放入默认schema中 |
targetEntity |
否 |
指定关联实体类名,默认情况下通过反射来判断关联实体类名 |
indexes |
否 |
@Index注解数组,为连接表定义多个索引 |
joinColumns |
否 |
可接受多个@JoinColumn,用于配置连接表中外键列的列信息,这些外键列参照当前实体对应表的主键列 |
inverseJoinColumns |
否 |
接受多个@JoinColumn,用于配置链接表中外键列信息,这些外键列参照当前实体的关联实体对应的主键列 |
uniqueConstrains |
否 |
为链接表增加唯一约束 |
Class Person{
//标识属性
@Id @Column(name="person_id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
//定义该Person实体关联的Address实体
@ManyToOne(targetEntity=Address.class)
//显式使用@JoinTable映射连接表
@JoinTable(name="person_address",//指定链接表的表名为person_address
//指定链接表中person_id外键列,参照当前实体对应表的主键列
joinColumns=@JoinColumn(name="person_id", referencedColumnName="person_id",unique=true),
//指定链接表中address_id外键列,参照到当前实体关联实体对应表的主键列
inverseJoinColumns=@JoinColumn(name="address_id", referencedColumnName="address_id")
)
private Address address;
}
二、 单向1-1关联
对于1-1关联 单/双项关联需要使用@OneToOne修饰代表关联实体的属性
@OneToOne支持的属性
属性 |
是否必须 |
说明 |
cascade |
否 |
指定Hibernate对关联实体采样怎样的级联策略 CascadeType.ALL:Hibernate将所有的持久化操作都级联到关联实体 CascadeType.MERGE:Hibernate将merge操作级联到关联实体 CascadeType.PERSIST: Hibernate将persist操作级联到关联实体 CascadeType.REFRESH: Hibernate将refresh操作级联到关联实体 CascadeType.REMOVE: Hibernate将remove操作级联到关联实体 |
tetch |
否 |
指定抓取关联实体时的抓取策略, FetchType.EAGER:立即抓取关联实体,默认 FetchType.LAZY: 延迟抓取关联实体。真正用到关联实体才抓取 |
MappedBy |
否 |
该属性合法的属性值为关联实体的属性名,该属性指定关联实体中哪个属性可引用到当前实体 |
orphanRemoval |
否 |
该属性设置是否删除孤儿实体。如果某个实体所关联的父实体不存在(既实体对应记录的外键为null),该实体就是所谓的孤儿实体 |
optional |
否 |
关联关系是否可选 |
targetEntity |
否 |
指定关联实体的类名。默认通过反射来判断关联实体名 |
1) 基于外键的单项1-1关联
Person class{}
//标识属性
@Id @Column(name="person_id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
//定义该Person实体关联的Address实体
@OneToOne(targetEntity=Address.class)
//显式使用@JoinTable映射连接表
@JoinTable(name="person_address",//指定链接表的表名为person_address
//指定链接表中person_id外键列,参照当前实体对应表的主键列
joinColumns=@JoinColumn(name="person_id", referencedColumnName="person_id",unique=true),
//指定链接表中address_id外键列,参照到当前实体关联实体对应表的主键列
inverseJoinColumns=@JoinColumn(name="address_id", referencedColumnName="address_id")
)
private Address address;
2) 有连接表的单项1-1关联
Person class{}
//标识属性
@Id @Column(name="person_id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
//定义该Person实体关联的Address实体
@OneToOne(targetEntity=Address.class)
//显式使用@JoinTable映射连接表
@JoinTable(name="person_address",//指定链接表的表名为person_address
//指定链接表中person_id外键列,参照当前实体对应表的主键列
joinColumns=@JoinColumn(name="person_id", referencedColumnName="person_id",unique=true),
//指定链接表中address_id外键列,参照到当前实体关联实体对应表的主键列
inverseJoinColumns=@JoinColumn(name="address_id", referencedColumnName="address_id")
)
private Address address;
三、 单项1-N关联
a) 无连接表的单项1-N关联
需要在N的一端增加外键列来维护关联关系,可在1的一端使用@JoinColumn修饰Set集合属性、映射外键列即可
Class person{
//标识属性
@Id @Column(name="person_id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
//定义该Person实体关联的Address实体,没有指定cascade属性
@OneToMany(targetEntity=Address.class)
//映射外键列,此处映射的外键列将会添加到关联实体对应的数据表中
@JoinColumn(name="address_id", refrencedColumnName="address_id",unique=true)
private Set<<Address> address = new HashSet<>();
}
b) 有连接表的单项1-N关联
Class Person{
//标识属性
@Id @Column(name="person_id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
//定义该Person实体关联的Address实体
@OneToMany(targetEntity=Address.class)
//显式使用@JoinTable映射连接表
@JoinTable(name="person_address",//指定链接表的表名为person_address
//指定链接表中person_id外键列,参照当前实体对应表的主键列
joinColumns=@JoinColumn(name="person_id", referencedColumnName="person_id",unique=true),
//指定链接表中address_id外键列,参照到当前实体关联实体对应表的主键列
inverseJoinColumns=@JoinColumn(name="address_id", referencedColumnName="address_id",unique=true)
)
private Address address;
}
四、单向N-N关联
单向N-N关联和1—N关联的持久化代码完全相同,控制关系的一端需要增加一个Set类型的属性,被关联的持久化实例以集合形式存在。
N-N关联需要使用@ManayToMany注解来修饰代表关联实体的集合属性,其属性如下
属性 |
是否必须 |
说明 |
cascade |
否 |
指定Hibernate对关联实体采样怎样的级联策略 CascadeType.ALL:Hibernate将所有的持久化操作都级联到关联实体 CascadeType.MERGE:Hibernate将merge操作级联到关联实体 CascadeType.PERSIST: Hibernate将persist操作级联到关联实体 CascadeType.REFRESH: Hibernate将refresh操作级联到关联实体 CascadeType.REMOVE: Hibernate将remove操作级联到关联实体 |
fetch |
否 |
指定抓取关联实体时的抓取策略, FetchType.EAGER:立即抓取关联实体,默认 FetchType.LAZY: 延迟抓取关联实体。真正用到关联实体才抓取 |
mappedBy |
否 |
该属性合法的属性值为关联实体的属性名,该属性指定关联实体中哪个属性可引用到当前实体 |
targetEntithy |
否 |
指定关联实体的类名。默认通过反射来判断关联实体名 |
、N-N关联必须使用连接表,与1-N关联相似,都要使用@JoinTable映射,区别是:N-N关联需要去掉@JoinTable中inverseJoinColumns中@JoinColumn的unique=true
@Entity
@Table(name="person_inf")
public class Person {
//标识属性
@Id @Column(name="person_id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
//定义该Person实体关联的Address实体
@ManyToMany(targetEntity=Address.class)
//映射连接表为person_address
@JoinTable(name="person_address",//指定链接表的表名为person_address
//定义链接表中名为person_id外键列,参照当前实体对应表的主键列
joinColumns=@JoinColumn(name="person_id", referencedColumnName="person_id",unique=true),
//指定链接表中address_id外键列,参照到当前实体关联实体对应表的主键列 没有指定unique=true
inverseJoinColumns=@JoinColumn(name="address_id", referencedColumnName="address_id",unique=true)
)
private Set<Address> address = new HashSet<>();
}
五、双向N-N关联
双向N-N关联需要两端都是用Set集合属性,两端都增加对集合属性的访问。只能使用链接表建立关联
双向N-N关联需要在两端分别使用@ManyToMany修饰Set集合属性,并在两端都使用@JoinTable显式映射链接表。在两端映射连接表时,两端指定的连接表的表明应该相同,而且两端都使用@JoinTable时指定的外键列的列名也是相互对应的。
如果希望某一段放弃控制关联关系,则可在这一端的@ManyToMany注解中指定mappedBy属性,这一端就无需、也不能使用@JoinTable映射连接表
例如:Person和Address都保持双向N-N关联关系
@Entity
@Table(name="person_inf")
public class Person {
//标识属性
@Id @Column(name="person_id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
//定义该Person实体关联的Address实体
@ManyToMany(targetEntity=Address.class)
//映射连接表为person_address
@JoinTable(name="person_address",//指定链接表的表名为person_address
//定义链接表中名为person_id外键列,参照当前实体对应表的主键列
joinColumns=@JoinColumn(name="person_id", referencedColumnName="person_id"),
//指定链接表中address_id外键列,参照到当前实体关联实体对应表的主键列 没有指定unique=true
inverseJoinColumns=@JoinColumn(name="address_id", referencedColumnName="address_id",unique=true)
)
private Set<EAddress> address = new HashSet<>();
}
Address实体
@Entity
@Table(name="address_inf")
public class Address {
@Id @Column(name="address_inf")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int addressId;
//定义地址详细信息的成员变量
private String addressDetail;
//定义该Address实体所有关联的Person实体
@ManyToMany(targetEntity=person.class)
//映射连接表、指定链接表的表名为person_address
@JoinTable(name="person_address",
//映射连接表中名为address_id的外键列
//该列参照当前实体对应表address_id主键列
joinColumns=@JoinColumn(name="address_id",referencedColumnName="address_id"),
//映射链接表中名为person_id的外键列
//该列参照当前实体对应表的person_id主键列
inverseJoinColumns=@JoinColumn(name="person_id",referencedColumnName="person_id"))
private Set<Person> persons = new HashSet<>()
}
六、双向1-1关联
双向1-1关联需要修改两端的持久化类代码,让两个持久化类都增加引用关联实体的属性,并为属性提供setter和getter方法
1.基于外键的双向1-1关联
对于双向1-1关联,两端都需要使用@OneToOne注解进行映射
对于基于外键的双向1-1关联,外键可以存放在任意一端。存放外键的一端,需要增加@JoinColumn注解来映射外键列,还应该增加@JoinColumn注解增加unique=true属性来表示该实体实际上是1的一端。
对于1-1的关联关系,两个实体原本处于平等状态;但选择任意一端增加外键(增加@JoinColumn注解的实体端),该表既变成从表,而另一个表则成为主表。
对于双向1-1的关联的主表对应的实体,不用于控制关联关系,主表对应的实体中使用@OneToOne注解时,应增加mappedBy属性------该属性表明该实体不管理关联关系,且不能使用@JoinColumn映射外键列
@Entity
@Table(name="person_inf")
public class Person {
//标识属性
@Id @Column(name="person_id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
//定义该Person实体关联的Address实体
@OneToOne(targetEntity=Address.class,mappedBy="person")
private Address address2;
}
@Entity
@Table(name="address_inf")
public class Address {
@Id @Column(name="address_inf")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int addressId;
//定义地址详细信息的成员变量
private String addressDetail;
//定义该Address实体所有关联的Person实体
@OneToOne(targetEntity=Person.class)
//用于映射person_id外键列,参照person_if表的person_id列
//指定了unique=true表明是1-1关联
@JoinColumn(name="person_id",referencedColumnName="person_id",unique=true)
private Person person;
}
2.有连接表的双向1-1关联
有连接表的双向1-1关联需要在两端分别使用@ OneToOne修饰代表关联实体的属性,并在两端都使用@JointTable显式映射连接表。在映射连接表时,两端指定的连接表的表名应该相同,而且两端使用@JoinTable时指定的外键列的列名也是相互对应的。
需要说明的是,如果程序希望某一端放弃控制关联关系,则可在这一端的@ OneToOne注解中指定mappedBy属性,这一端就无须、也不能使用@JoinColumn映射连接表了。由于此时是1-1关联,因此使用@ JoinTable注解时指定的@ JoinColum都需要增加 unique=true.
@Entity
@Table(name="person_inf")
public class Person {
// 标识属性
@Id @Column(name="person_id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
//定义该Person实体关联的Address实体
@OneToOne(targetEntity=Address.class)
//映射底层连接表,表名为person_address
@JoinTable(name="person_address",//
//映射链接表的外键列,增加unique=true表明是1-1关联
joinColumns=@JoinColumn(name="person_id", referencedColumnName="person_id",unique=true),
//映射链接表的外键列,增加unique=true表明是1-1关联
inverseJoinColumns=@JoinColumn(name="address_id", referencedColumnName="address_id",unique=true)
)
private Address address2;
}
@Entity
@Table(name="address_inf")
public class Address {
@Id @Column(name="address_inf")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int addressId;
//定义地址详细信息的成员变量
private String addressDetail;
//定义该Address实体所有关联的Person实体
@OneToOne(targetEntity=Person.class)
//映射底层连接表,表名为person_address 指定了unique=true表明是1-1关联
@JoinTable(name="person_address",//
//映射链接表的外键列,增加unique=true表明是1-1关联
joinColumns=@JoinColumn(name="address_id", referencedColumnName="address_id",unique=true),
//映射链接表的外键列,增加unique=true表明是1-1关联
inverseJoinColumns=@JoinColumn(name="person_id", referencedColumnName="person_id",unique=true))
private Person person;
}
七、双向1-N关联
对于1-N关联, Hibernate推荐使用双向关联,而且不要让1的一端控制关联关系,而使用N的
控制关联关系。双向的1-N关联与N-1关联是完全相同的两种情形,两端都需要地加对关联属性的访间,N的一端增加引用到关联实体的属性,1的一端增加集合属性,集合元素为关联实体
Hibernate同样对这种双向关联映射提供了两种支持:有连接表的和无连接表的,
1.无连接表的双向1-N关联
无连接表的双向1-N关联,N的一端需要增加 @Many ToOne注解来修饰代表关联实体的属性,而1的一端则需要使用@ OneToMany注解来修饰代表关联实体的属性关系,实际上只需要在N的底层数据库为了记录这种1-N关联既可,因此应该在使用@ ManyToOne注解的同时,使用@JoinColumn来映射外键。
前面己经提到,对于双向的1-N关联映射,通常不应该允许1的一端控制关联关系,而应该由N的一端来控制关联关系,因此应该在使用@OneToMany注解时指定 mappedBy属性-------一旦为@OneToMany, @ManyToMany指定了该属性,则表明当前实体不能控制关联关系,当@OneToMany@ManyToMany、@OneToOne所在的当前实体放弃控制关联关系之后, Hibernate就不允许使用@JoinColumn或@ JoinTable修饰代表关联实体的属性了。
对于指定了 mappedBy属性的@ OneToMany.@ ManyToMamy、@OneToOne注解不能与@ JoinColum或@ JoinTable同时修饰代表关联实体的属性
@Entity
@Table(name="person_inf")
public class Person {
标识属性
@Id @Column(name="person_id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
//定义该Person实体关联的Address实体
//指定mappedBy属性表明该Person实体不控制关联关系
@OneToMany(targetEntity=Address.class,mappedBy="person")
private Set<Address> address = new HashSet<>();
}
@Entity
@Table(name="address_inf")
public class Address {
@Id @Column(name="address_inf")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int addressId;
//定义地址详细信息的成员变量
private String addressDetail;
//定义该Address实体所有关联的Person实体
@ManyToOne(targetEntity=Person.class)
//定义名为person_id外键列,参照person_inf表的person_id列
//指定了unique=true表明是1-1关联
@JoinColumn(name="person_id",referencedColumnName="person_id",nullable=false)
private Person person;
}
2.有连接的双向1-N关联
有连接的双向1-N关联,1的一端无需任何改变;只要在N的一端使用@JoinTable显式指定连接表即可。
@Entity
@Table(name="address_inf")
public class Address {
@Id @Column(name="address_inf")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int addressId;
//定义地址详细信息的成员变量
private String addressDetail;
//定义该Address实体所有关联的Person实体
@ManyToOne(targetEntity=Person.class)
//映射连接表,指定连接表为person_address
// @JoinTable(name="person_address",//
// //指定连接表中address_id列参照当前实体对应数据表的address_id主键列
// joinColumns=@JoinColumn(name="address_id", referencedColumnName="address_id",unique=true),
// //指定连接表中person_id列参照当前实体关联实体的对应数据表的person_id主键列
// inverseJoinColumns=@JoinColumn(name="person_id", referencedColumnName="person_id"))
private Person person;
}
@Entity
@Table(name="person_inf")
public class Person {
//标识属性
@Id @Column(name="person_id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
//定义该Person实体关联的Address实体
@OneToMany(targetEntity=Address.class)
//映射底层连接表,表名为person_address
@JoinTable(name="person_address",//
//指定连接表中address_id列参照当前实体对应数据表的person_id主键列
joinColumns=@JoinColumn(name="person_id", referencedColumnName="person_id"),
//指定连接表中address_id列参照当前实体关联实体的对应数据表的address_id主键列
inverseJoinColumns=@JoinColumn(name="address_id", referencedColumnName="address_id",unique=true)
)
private Set<Address> address = new HashSet<>();
}
对于所有的依赖关系期望先持久化一的一端,再持久化N的一端,或者先持久化被依赖的一端