一直對資料庫映射這塊缺乏練習,導緻在實踐中總是卡在一個某個具體的問題上。是以這裡花上一小段時間将映射這塊練習一下,友善日後回顧。
環境準備:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.automannn</groupId>
<artifactId>hibernateRelationShipPractice</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
</project>
資料源,目錄,以及啟動類:
package com.automannn;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
*
* @time 2018/10/20 16:51
*/
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class);
}
}
一對一單向映射的練習:
設 一個學校有且僅有一個校長,一個校長僅能任職于一個學校。 是以他們就構成了一對一的關系。
package com.automannn.entity;
import javax.persistence.*;
/**
*
* @time 2018/10/20 17:08
*/
@Entity
public class HeadMaster {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String headMasterName;
@OneToOne
private School school;
}
package com.automannn.entity;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
/**
*
* @time 2018/10/20 17:07
*/
@Entity
public class School {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String schoolName;
}
這個時候,校長是主要方,持有學校的資訊。運作之後查表:
在這種場合下,我們可以通過主要方檢視另一方的資訊。即通過校長檢視到相應的學校資訊。 反之,若學校為主要方,那麼相應的也要反轉,這是單向的。 并且他們的聯系是通過外鍵關聯的,但是我看到很多的部落格都說不要使用外鍵,關系的對應通過程式控制。
一對一雙向映射練習:
package com.automannn.entity;
import javax.persistence.*;
/**
* @author
* @time 2018/10/20 17:08
*/
@Entity
public class HeadMaster {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String headMasterName;
@OneToOne(mappedBy = "headMaster")
private School school;
}
package com.automannn.entity;
import javax.persistence.*;
/**
* @time 2018/10/20 17:07
*/
@Entity
public class School {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String schoolName;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "headMaster_id")
private HeadMaster headMaster;
}
它們的表結構如下:
要注意,将hibernate在update狀态下,貌似對于删除表結構的操作可能有缺陷,是以導緻我測試浪費了一些時間。
最簡形式:
同時,注解的屬性與類中的屬性通過程式上下文聯系起來。 不具有固定性!!! 後面思考了下,這種說法不準确,雖然是上下文,但是屬性變量實際上是起到了一個管道的作用,是以要寫的對應關系還是很好了解的了。
多與一的常見關系映射練習:
設: 某個班具有多個學生,每個學生隻能屬于一個班。 是以,構成了這樣的一個多與一的映射關系。
現有一個需求如下:
需要知道每個班有哪些學生? 那麼可以通過單向一對多,單向多對一考慮。
單向一對多:
package com.automannn.entity;
import javax.persistence.*;
import java.util.List;
/**
* @author
* @time 2018/10/20 16:53
*/
@Entity
public class Clazz {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String clazzName;
@OneToMany
private List<Student> studentList;
}
package com.automannn.entity;
import javax.persistence.*;
/**
* @author [email protected]
* @time 2018/10/20 16:52
*/
@Entity
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
}
這種情況下,它生成的表結構:
會生成一張隻具有外鍵的中間表。 并不是我們想要的效果。
這是在具有最簡注解:
的情況。
當我們在Clazz.class修改如下:
可以發現它的表結構:
可以發現一個現象,就是我們的那個joinColumn是在 Clazz.class實體寫的,但是加入的屬性列在Student表中。 因為,隻要是一與多的關系,hibernate都是在多的一方記錄資訊。
一緻性維護由哪一方完成,因為這裡涉及到性能的問題。但是由于這裡是單向的關系,jpa規範應該是預設由多的一方完成吧,因為在注解中沒找到inverse屬性,同時看網上的解釋也有:
是以就不再去看了。 另外要注意,mappedBy 與 joinColumn不能同時出現,會報錯。mappedBy隻适用于雙向關系的那種可能。
最簡配置:
結構:
以上可以滿足通過班級查詢學生,而且是比較直覺的了解。
那麼,多對一實際也可以滿足這種需求。
單向一對多的練習:
package com.automannn.entity;
import javax.persistence.*;
/**
* @author
* @time 2018/10/20 16:52
*/
@Entity
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
@ManyToOne
private Clazz clazz;
}
package com.automannn.entity;
import javax.persistence.*;
import java.util.List;
/**
* @author
* @time 2018/10/20 16:53
*/
@Entity
public class Clazz {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String clazzName;
}
它生成的表結構:
這種情況下,我們實際上是去查詢學生表,将班級以屬性的方式進行查詢的。
查詢班級表,以清單方式直覺的将本班級學生給查詢出來。
都能夠對兩個表的資訊進行增删該查。 并且表的結構也一樣,隻是查詢的邏輯不同,還有就是性能方面可能有一些不同。
由于我并沒有很多的實戰經驗,但是我的感覺是,當查詢的請求為主時,完全可以使用單向一對多的方式将所有的資訊給查出來。否則,當以資料更新操作為主的時候,應該使用單向多對一的方式。
Ok,如果有另一個需求,需要知道每個學生所在的班級資訊。 也就是需要從多的一端擷取一的資料。這個時候可以這樣幹,那就是在根本上修改這種一與多的關系,導緻它變長多與多的關系,形成一個回環。 但是這樣很明顯是不明智的。正确的做法應該是使用雙向關系。因為這裡是雙向的,是以也就不存在方向性了,因為它的表結構都是一樣的。
雙向多與一映射關系練習:
package com.automannn.entity;
import javax.persistence.*;
import java.util.List;
/**
* @author
* @time 2018/10/20 16:53
*/
@Entity
public class Clazz {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String clazzName;
@OneToMany(mappedBy = "clazz")
private List<Student> studentList;
}
package com.automannn.entity;
import javax.persistence.*;
/**
* @aut
* @time 2018/10/20 16:52
*/
@Entity
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
@ManyToOne
private Clazz clazz;
}
它生成的表結構:
注意一下,@ManyToOne是沒有mappedBy屬性的。
fetch屬性一般預設即可,因為預設的都是推薦的。
可以說,雙向的這種一與多的關系簡直就是我們的理想狀态了。 并且将維護關系設定為多的一方,那我們就可以很友善,愉快的進行開發哈哈哈。 都說對性能有影響,但是我覺得性能是一個虛的概念,當業務需求根本不可能到達瓶頸的時候,性能問題根本不是問題了。
很開心愉快的進行了一對一單雙向,一對多單向,多對一單向,一與多雙向的練習。 接下來就進入最後一個的練習。 多對多映射。
多對多映射的練習:
設:一個老師有多個學生,一個學生可以被多個老師教。 是以他們就構成了一種多對多的關系。
在這種多對多的關系中,我們經常要通過一方查詢另一方的需求,是以也就不考慮單雙向的問題了。
但是發現多對多關系中是存在單雙向問題的:
package com.automannn.entity;
import javax.persistence.*;
import java.util.List;
/**
* @author
* @time 2018/10/20 19:29
*/
@Entity
public class Teacher {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String teacherName;
@ManyToMany
private List<Student> student;
}
package com.automannn.entity;
import com.automannn.before.Clazz;
import javax.persistence.*;
/**
* @author [email protected]
* @time 2018/10/20 16:52
*/
@Entity
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
}
生成的表結構如下:
這是單向的情況。 接着修改代碼,使之變為雙向,以滿足業務需求。
package com.automannn.entity;
import javax.persistence.*;
import java.util.List;
/**
* @author
* @time 2018/10/20 19:29
*/
@Entity
public class Teacher {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String teacherName;
@ManyToMany(mappedBy ="teacherList" )
private List<Student> studentList;
}
package com.automannn.entity;
import com.automannn.before.Clazz;
import javax.persistence.*;
import java.util.List;
/**
* @time 2018/10/20 16:52
*/
@Entity
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
@ManyToMany
private List<Teacher> teacherList;
}
它的表結構: