标签:
一 分类
Hibernate的关联关系可分为:单向关联和双向关联
单向关联包括:1->1 1->N N->1 N->N
双向关联包括:1->1 1->N N->N
二 单向N->1关联
1.程序应该在N的一端的持久化类中增加一个属性,该属性引用1的一端的关联实体
对于N->1关联,都需要在N的一端使用@ManyToOne修饰代表关联实体的属性,该注解可以指定以下属性:
(1)cascade:指定Hibernate对关联实体采用怎样的级联策略,包括以下五种情况:
CascadeType.ALL:将所有的持久化操作都级联到关联实体
CascadeType.MERGE:将merge操作都级联到关联实体
CascadeType.PERSIST:将persist操作都级联到关联实体
CascadeType.REFRESH:将refresh操作都级联到关联实体
CascadeType.REMOVE:将所remove操作都级联到关联实体
(2)fetch:指定抓取关联实体时的抓取策略
FetchType.EAGER:立即抓取
FetchType.LAZY:延迟抓取
(3)optional:指定关联关系是否可选
(4)targetEntity:指定关联实体的类名。默认情况下会通过反射来判断关联实体的类名
注意:大部分时候无需指定targetEntity,但是如果使用@OneToMany或@ManyToMany修饰的1--N N--N关联,使用Set集合不带泛型信息,就必须指定targetEntity属性
2.无连接表的N--1关联
只要在N的一端增加一列外键,让外键值记录该对象所属的实体即可。可以使用@JoinColumn来修饰代表关联实体的属性,它主要用于映射底层的外键列。
Person.java
@Entity
@Table(name="person_info")
public class Person {
@Id
@Column(name="person_id")
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
private String name;
private int age;
@ManyToOne(targetEntity=Address.class)
@JoinColumn(name="address_id",nullable=false)
@Cascade(CascadeType.ALL)
private Address address;
...//此处省略getter/setter等其他方法
}
Address.java
@Entity
@Table(name="address_info")
public class Address {
@Id
@Column(name="address_id")
@GeneratedValue(strategy=GenerationType.AUTO)
private int addressId;
private String adressDetail;
...//此处省略getter/setter等其他方法
}
别忘了配置文件hibernate.cxf.xml加上:
<hibernate-configuration>
<session-factory>
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql:///mydb</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">123456</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<property name="show_sql">true</property>
<property name="hibernate.format_sql">false</property>
<mapping class="myHibernate.Person"/>
<mapping class="myHibernate.Address"/>
</session-factory>
</hibernate-configuration>
测试:
public class myTest {
public static void main(String[] args) {
Configuration config=new Configuration().configure();
SessionFactory factory=config.buildSessionFactory();
Session session=factory.openSession();
Transaction tx=session.beginTransaction();
Person p=new Person();
p.setName("lyy");p.setAge(22);
Address a=new Address("北京"); //创建一个瞬态的Address对象
p.setAddress(a);
session.save(p);
Address a2=new Address("南京");
p.setAddress(a2);
tx.commit();
session.close();
}
}
注意:系统在保存Person对象时,要向person_info表中插入address记录,但是此时address处于瞬态,此时会有两种状况发生:抛出异常object references an unsaved transient instance - save the transient instance before flushing,因为主表记录不曾插入,所以参照该记录的从表记录无法插入;系统自动级联插入主表记录,再插入从表记录。我们在程序中有这样一行:@Cascade(CascadeType.ALL),这就意味着系统会先自动插入主表记录,即先持久化Address对象,再持久化Person对象。
3.有连接表的N--1关联
程序需要显式使用@JoinTable注解来映射连接表,它的属性如下:
name:连接表的表名
catalog schema indexes uniqueConstraints 与其他的一样
targetEntity:指定关联实体的类名
joinColumns:可接受多个@joinColumn,用于配置连接表中外键列的列信息,这些外键列参照当前实体对应表的主键列
inverseJoinColumn:可接受多个@joinColumn,用于配置连接表中外键列的列信息,这些外键列参照当前实体的关联实体对应表的主键列
将Person.java修改为:
@Entity
@Table(name="person_info")
public class Person {
@Id
@Column(name="person_id")
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
private String name;
private int age;
@ManyToOne(targetEntity=Address.class)
@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"))
@Cascade(CascadeType.ALL)
private Address address;
...
}
三 单向1--1关联
需要使用@OneToOne修饰代表关联实体的属性,它的属性有:
cascade fetch targetEntity同上
mappedBy:该属性合法的属性值为关联实体的属性名,该属性指定关联实体中哪个属性克引用到当前实体
orphanRemoval:设置是否删除“孤儿”实体。如果一个实体所关联的父实体不存在,即该实体对应记录的外键为null,该实体就是所谓的“孤儿”实体
optional:指定关联关系是否可选
person.java
@Entity
@Table(name="person_info")
public class Person {
@Id
@Column(name="person_id")
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
private String name;
private int age;
@OneToOne(targetEntity=Address.class)
@JoinColumn(name="address_id",referencedColumnName="address_id",unique=true)
@Cascade(CascadeType.ALL)
private Address address;
...
}
四 单向1--N关联
该关联的持久化实体中要使用集合属性,因为1的一端需要访问N的一端,而N的一端将以集合Set的形式出现。我们只需要在1的一端增加Set类型的成员变量,该成员变量记录当前实体所有的关联实体。
我们需要使用@OneToMany注解,该注解的属性如下:
cascade fetch orphanRemoval mappedBy targetEntity
1.无连接表的单向1--N关联
person.java
@Entity
@Table(name="person_info")
public class Person {
@Id
@Column(name="person_id")
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
private String name;
private int age;
@OneToMany(targetEntity=Address.class)
@JoinColumn(name="person_id",referencedColumnName="person_id")
private Set<Address> addresses=new HashSet<>();
...
}
测试:
public class myTest {
public static void main(String[] args) {
Configuration config=new Configuration().configure();
SessionFactory factory=config.buildSessionFactory();
Session session=factory.openSession();
Transaction tx=session.beginTransaction();
Person p=new Person();
Address a=new Address("北京");
session.persist(a);
p.setName("lyy");p.setAge(22);
p.getAddresses().add(a);
session.save(p);
Address a2=new Address("南京");
session.persist(a2);
p.getAddresses().add(a2);
tx.commit();
session.close();
}
}
注意:上面这个程序Hibernate会采用两条SQL语句完成:一条insert语句插入一个外键为null的address_info记录;一条Update语句修改刚刚插入的address_info记录,这会造成系统性能不佳。
单向无连接表的1--N关联,由于Address实体并不知道它所关联的Person实体,程序只是把Address实体添加到Person实体的address集合属性中,因此hibernate无法在执行insert into address_info时为该外键列指定值。解决方案:可以进行双向1--N关联,或者是采用有连接表的1--N单向关联。
2.有连接表的单向1--N关联
@Entity
@Table(name="person_info")
public class Person {
@Id
@Column(name="person_id")
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
private String name;
private int age;
@OneToMany(targetEntity=Address.class)
@JoinTable(name="person_address",
joinColumns=@JoinColumn(name="person_id",referencedColumnName="person_id"),
inverseJoinColumns=@JoinColumn(name="address_id",referencedColumnName="address_id",unique=true))
private Set<Address> addresses=new HashSet<>();
...
}
五 单向N--N关联
单向N--N关联与1--N关联的持久化代码完全相同,控制关系的一端需要增加一个Set类型的属性,被关联的持久化实例以集合形式存在。
使用@ManyToMany注解来修饰代表关联实体的集合属性,其属性如下:
cascade fetch mappedBy targetEntity与之前的相似,不一一介绍
,注意不能使用unique=true
@Entity
@Table(name="person_info")
public class Person {
@Id
@Column(name="person_id")
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
private String name;
private int age;
@ManyToMany(targetEntity=Address.class)
@JoinTable(name="person_address",
joinColumns=@JoinColumn(name="person_id",referencedColumnName="person_id"),
inverseJoinColumns=@JoinColumn(name="address_id",referencedColumnName="address_id"))
private Set<Address> addresses=new HashSet<>();
...
}
标签:
原文地址:http://www.cnblogs.com/lyy-2016/p/5723228.html