Hibernate关联关系注解配置
什么是关联关系?关联关系有哪几种?
关联关系指实体之间的关系,也就是表与表之间的关系。一个关系用两个属性来描述,数量性和方向性。
从数量上来看,表与表之间主要有三种关系,一对一,一对多,多对多。
加上关系的方向,还有一个多对一。
hibernate中关联关系的维护
在实际的业务开发中,对于两个有关联的数据库实体,比如学生对教室,我们通常还需要在操作一方时,维护两方彼此之间的关系。
关系的维护分为两类:
1.级联Cascade,在操作一方时,是否对另一方也执行同样的操作。
2.外键的维护inverse,在操作一方时,是否自动维护外键关系。比如如果将 多方的对象添加给以一的一方,因为外键由多方维护,hibernate为了保证添加的这个多方对象的外键是正确的,会自动给这个多方的外键设置值(也就是一的一方的主键)
外键维护,在xml配置中使用inverse属性,在注解中使用mappedBy注解来声明。
cascade与inverse
1.cascade,指把对当前对象的操作 级联到 关联对象上。
一般在one to one ,one to many设置级联。
配置了这个属性后,当对当前对象执行如save等更新数据库的操作时,当前实体所关联的实体也会执行相应的操作。
2.inverse
默认值为true, 表示让对方来维护关系。设为false,自己维护关系。
inverse主要有两个作用:
1)维护外键
主控方保存时,是否自动update被控方的外键字段。外键字段指向的就是当前保存的实体。
2)维护级联
决定当前设置的级联是否有用,自己维护关系时,对方设置的级联就不会生效,对方保存时不会让本方也保存。而对方维护关系,则与此相反。
@mappedBy注解
1)mappedBy(name="对方标准代表当前实体的属性“)
2)只存在于OneToOne,OneToMany,ManyToMany, 不能在ManyToOne中
3)与joincolumn或jointable互斥。因为joincolumn在拥有方声明了被拥有方,而mappedby定义在被拥有方,指向拥有方。
4)一般拥有方为拥有外键的那一方,在一对多中是在多方。
有什么用:
让拥有方来自动维护与当前实体的关系。与inverse对应。inverse=true
在注解中没有设置mappedBy时,默认双方都维护关系,就如inverse。
如何确定单向与双向关联
在实际开发中,是采用单向关联还是双向关联,要看具体的业务需求,如果业务只需要在获取一方的实体时获取另一方的实体,而不是两边都能获取,那就采用单向关联。反之,如果需要在两边的实体中都能获取到对方,就使用双向关联。
一对一
双向关联,每一方都能获取到对方的实体
// CREATE TABLE `person` (
// `id` varchar(255) NOT NULL,
// `pname` varchar(255) DEFAULT NULL,
// `idcard` varchar(255),(外键)
// PRIMARY KEY (`id`)
// ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
// CREATE TABLE `idcard` (
// `id` varchar(255) NOT NULL,
// `cardnum` varchar(255) DEFAULT NULL,
// PRIMARY KEY (`id`)
// ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
@Entity
@Table(name="person")
public class Person {
@Id
@GenericGenerator(name="uuidGenerator", strategy="uuid")
@GeneratedValue(generator="uuidGenerator")
private String id;
@Column(name="pname")
private String pname;
@OneToOne(cascade=CascadeType.ALL)
@JoinColumn(name="idcard")
private IdCard card;
}
@Entity
@Table(name="idcard")
public class IdCard {
@Id
@GenericGenerator(name="uuidGenerator", strategy="uuid")
@GeneratedValue(generator="uuidGenerator")
private String id;
@Column(name="cardNum")
private String cardNum;
@OneToOne
@mappedBy(name="card")
private Person person;
}
单向关联,一般让外键所在的表作为主控方。
@Entity
@Table(name="person")
public class Person {
@Id
@GenericGenerator(name="uuidGenerator", strategy="uuid")
@GeneratedValue(generator="uuidGenerator")
private String id;
@Column(name="pname")
private String pname;
@OneToOne(cascade=CascadeType.ALL)
@JoinColumn(name="idcard")
private IdCard card;
}
@Entity
@Table(name="idcard")
public class IdCard {
@Id
@GenericGenerator(name="uuidGenerator", strategy="uuid")
@GeneratedValue(generator="uuidGenerator")
private String id;
@Column(name="cardNum")
private String cardNum;
// 单向关联,这边不用保存对方的引用
}
一对多
// 表,多个student对应一个class
CREATE TABLE `student` (
`id` varchar(255) NOT NULL,
`name` varchar(255) DEFAULT NULL,
`classId` varchar(255),(外键)
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `class` (
`id` varchar(255) NOT NULL,
`nane` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
@Entity
@Table(name="person")
public class Person {
CREATE TABLE `teacher` (
`id` varchar(255) NOT NULL,
`name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `teacher_to_student` (
`id` varchar(255) NOT NULL,
`tid` varchar(255) NOT NULL,
`sid` varchar(255)NOT NULL
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
一对多,多对一双向关联,单向关联只需要去掉一的那方对多方的引用。
@Entity
@Table(name="student")
public class Student {
@Id
@GenericGenerator(name="uuidGenerator", strategy="uuid")
@GeneratedValue(generator="uuidGenerator")
private String id;
@Column(name="name")
private String name;
@ManyToOne(cascade=CascadeType.ALL)
@JoinColumn(name="classId")
private StudentClass class;
}
@Entity
@Table(name="class")
public class StudentClass {
@Id
@GenericGenerator(name="uuidGenerator", strategy="uuid")
@GeneratedValue(generator="uuidGenerator")
private String id;
@Column(name="name")
private String name;
@OneToMany
//mappedBy和Joincolumn互斥
// mappedBy在一的一方
@mappedBy(name="classId")
private List students;
}
多对多关联。分为两种情况:
1.建立一个中间表,并为中间表建立持久化类。这样就拆分成了两个多对一关联,配置如上。
2.不为中间表建立持久化类,而是交给hibernate去维护。
主控方:
@ManyToMany
@joinTable表示中间表
joinColumns 表示 当前实体在中间表的外键
inverseJoincolumns 关联的另一方在中间表的外键
被控方:
ManyToMany(@MappedBy=主控方对象持有的被控方的属性名)
@Entity
@Table(name="student")
public class Student {
@Id
@GenericGenerator(name="uuidGenerator", strategy="uuid")
@GeneratedValue(generator="uuidGenerator")
private String id;
@Column(name="name")
private String name;
@ManyToOne(cascade=CascadeType.ALL)
@JoinTable(name = "teacher_to_student",
joinColumns = @JoinColumn(name = "sid"),
inverseJoinColumns = @JoinColumn(name = "tid"))
private Set teachers;
}
@Entity
@Table(name="teacher")
public class Teacher {
@Id
@GenericGenerator(name="uuidGenerator", strategy="uuid")
@GeneratedValue(generator="uuidGenerator")
private String id;
@Column(name="name")
private String name;
@ManyToMany(mappedBy="teachers",cascade=CascadeType.ALL)
private Set student;
}