1.對象設(shè)計
Employee 實體
@Entity
@Setter
@Getter
public class Employee {
@Id
@GeneratedValue
private Long id;
private String name;//名稱
@Override
public String toString() {
return "Employee{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
Department 實體
@Getter
@Setter
@ToString
@Entity
public class Department {
@Id
@GeneratedValue
private Long id;
private String name;
@OneToMany//建立關(guān)聯(lián)一對多
private List<Employee> employees = new ArrayList<>();
@Override
public String toString() {
return "Department{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
2.表的結(jié)構(gòu)

3.實現(xiàn)
向表中添加數(shù)據(jù):
(1):先保存部門,再保存員工
@Test
public void testsave(){
EntityManager entityManager = JPAUtil.createEntityManager();
//創(chuàng)建一方
Department department = new Department();
department.setName("行政部");
//創(chuàng)建多方
Employee e1 = new Employee();
e1.setName("lucy");
Employee e2 = new Employee();
e2.setName("cici");
department.getEmployees().add(e1);
department.getEmployees().add(e2);
//持久化
entityManager.persist(department);
entityManager.persist(e1);
entityManager.persist(e2);
entityManager.getTransaction().begin();
entityManager.getTransaction().commit();
entityManager.close();
}
(2):先保存員工,再保存部門
@Test
public void testsave(){
EntityManager entityManager = JPAUtil.createEntityManager();
//創(chuàng)建一方
Department department = new Department();
department.setName("行政部");
//創(chuàng)建多方
Employee e1 = new Employee();
e1.setName("lucy");
Employee e2 = new Employee();
e2.setName("cici");
department.getEmployees().add(e1);
department.getEmployees().add(e2);
//持久化
entityManager.persist(e1);
entityManager.persist(e2);
entityManager.persist(department);
entityManager.getTransaction().begin();
entityManager.getTransaction().commit();
entityManager.close();
}
4.添加SQL分析
(1):先保存部門,再保存員工
Hibernate: insert into Department (name) values (?)
Hibernate: insert into Employee (name) values (?)
Hibernate: insert into Employee (name) values (?)
Hibernate: update Employee set dept_id=? where id=?
Hibernate: update Employee set dept_id=? where id=?
執(zhí)行了5條SQL:
(2):先保存員工,再保存部門
Hibernate: insert into Employee (name) values (?)
Hibernate: insert into Employee (name) values (?)
Hibernate: insert into Department (name) values (?)
Hibernate: update Employee set dept_id=? where id=?
Hibernate: update Employee set dept_id=? where id=?
發(fā)現(xiàn)不管是先保存一方還是多方都會發(fā)送5條SQL,因為外鍵id是由一方來管理,所以它必須執(zhí)行相應(yīng)的update更新操作!
5.查詢的SQL分析
@Test
public void testFind(){
EntityManager entityManager = JPAUtil.createEntityManager();
//獲取一方
Department department = entityManager.find(Department.class, 1l);
entityManager.close();
}
發(fā)送的SQL
Hibernate : SELECT
employee0_.id AS id1_1_0_,
employee0_. NAME AS name2_1_0_
FROM
Employee employee0_
WHERE
employee0_.id =?
并沒有去執(zhí)行查詢多方的信息,說明默認是延遲加載!
@Test
public void testFind(){
EntityManager entityManager = JPAUtil.createEntityManager();
//獲取一方
Department department = entityManager.find(Department.class, 1l);
entityManager.close();
System.out.println(department.getEmployees());
}
拋出異常:延遲初始化異常,也說明了默認是延遲加載
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: hanfengyi.one2many.Department.employees, could not initialize proxy - no Session
6.判斷集合中的數(shù)據(jù)
通過一方獲取多方,判斷集合是否有數(shù)據(jù)!不能夠直接判斷是否為null,因為在實體中為防止報錯,已經(jīng)初始化了。所以無論如何它都不為null。
@Test
public void testFind(){
EntityManager entityManager = JPAUtil.createEntityManager();
//獲取一方
Department department = entityManager.find(Department.class, 1l);
if(department.getEmployees().size()!=0){
System.out.println("有數(shù)據(jù)");
}
entityManager.close();
}
7.集合映射
List集合
@Test
public void testLMapping(){
EntityManager entityManager = JPAUtil.createEntityManager();
Department department = entityManager.find(Department.class, 1l);
System.out.println(department.getEmployees().getClass());//class org.hibernate.collection.internal.PersistentBag
entityManager.close();
}
Set集合
@Test
public void testLMapping(){
EntityManager entityManager = JPAUtil.createEntityManager();
Department department = entityManager.find(Department.class, 1l);
System.out.println(department.getEmployees().getClass());//class org.hibernate.collection.internal.PersistentSet
entityManager.close();
}
這里是Hibernate為了實現(xiàn)延遲加載而提供的類
org.hibernate.collection.internal.PersistentSet 實現(xiàn)了java.util.Set接口
org.hibernate.collection.internal.PersistentBag 實現(xiàn)了java.util.List接口
我們聲明集合的時候必須使用接口,因為Hibernate是用它自己的List/Set實現(xiàn)類PersistentBag /PersistentSet 來接收數(shù)據(jù)!如果我們直接使用實現(xiàn)類初始化,PersistentBag /PersistentSet 和ArrayList/HashSet是平級的,會拋出異常。
8.List映射
Set:無序不重復(fù)
List:有序可重復(fù)
使用List集合排序的方式:
在集合的上方使用注解 @OrderBy("參數(shù)為多方需要排序的屬性名")
@Getter
@Setter
@ToString
@Entity
public class Department {
@Id
@GeneratedValue
private Long id;
private String name;
@OneToMany//建立關(guān)聯(lián)一對多
@JoinColumn(name = "dept_id")//指定關(guān)聯(lián)列的名字
@OrderBy("name")//將name屬性進行排序,默認是升序
private List<Employee> employees = new ArrayList<>();
@Override
public String toString() {
return "Department{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
@Test
public void testFind(){
EntityManager entityManager = JPAUtil.createEntityManager();
//獲取一方
Department department = entityManager.find(Department.class, 1l);
if(department.getEmployees().size()!=0){
System.out.println("有數(shù)據(jù)");
System.out.println(department.getEmployees());
//結(jié)果:[Employee{id=2, name='cici'}, Employee{id=1, name='lucy'}]
}
entityManager.close();
}
小結(jié):
1.一對多與多對一的表的結(jié)構(gòu)是一樣的,只是站的角度不同。
2.一對多的關(guān)聯(lián)方式使用注解@OneToMany,jpa會采取生成中間表來關(guān)聯(lián)。
3.在一方使用@JoinColumn(name = " ")指定關(guān)聯(lián)列的名字,就不會生成中間表。
4.無論是先保存一方還是先保存多方,執(zhí)行的SQL語句條數(shù)是一樣的!因為外鍵是由一方來處理的,所以一對多的性能很差,推薦使用雙向!
5.一對多默認是延遲加載,因為多方是集合,延遲加載可以很好的節(jié)約性能!
6.集合必須使用接口聲明,因為Hibernate要用到他自己的實現(xiàn)類來接收數(shù)據(jù)!
7.判斷集合中的數(shù)據(jù)不能直接判斷為null,因該判斷它的size是否不等于0!
8.List集合可以使用注解@OrderBy("參數(shù)為多方需要排序的屬性名")對指定的屬性排序!