在做項目的時候遇到這樣一個問題:
一個學生表stuInfo,一個專業表majorInfo。使用MySQL數據庫,表定義如下:
列名 | 數據類型 | 功能 |
---|---|---|
id | bigint | 學生信息的絕對索引,自增列,主鍵 |
stuId | varchar(10) | 學號列 |
stuName | varchar(10) | 學生姓名列 |
majorId | varchar(5) | 學生專業ID列,由於專業ID中可能出現英文字母來區分專科專業和本科專業,因此不能使用數值類型 |
列名 | 數據類型 | 功能 |
---|---|---|
id | bigint | 專業信息的絕對索引,自增列,主鍵 |
majorId | varchar(5) | 學生專業ID列,由於專業ID中可能出現英文字母來區分專科專業和本科專業,因此不能使用數值類型 |
majorName | varchar(15) | 專業名稱列 |
有項目經驗的人一看就知道這樣建立數據庫是非常不專業的,外鍵關聯沒問題,問題在於關聯列的數據類型是varchar,這將非常消耗計算資源。
但是本人也沒有辦法,爲了和原有系統兼容,儘快實現功能,也只好犧牲性能了。在這裏也提醒讀者,凡是涉及表關聯操作的,關聯列的數據類型儘量採用數值。當數據庫內記錄很多的時候,執行連接select語句時,使用數值類型進行關聯較之使用字符類型進行關聯將會產生很大的性能差異。
要求是這樣的,將stuInfo表中的majorId與majorInfo表中的majorId進行關聯,以實現按照學號查詢學生時能顯示所在專業。
開始的時候我的POJO是這樣來寫的
stuInfo表的POJO:
- package pojo;
- import java.io.Serializable;
- import javax.persistence.Entity;
- import javax.persistence.GeneratedValue;
- import javax.persistence.Id;
- import javax.persistence.JoinColumn;
- import javax.persistence.ManyToOne;
- @Entity
- public class StuInfo implements Serializable{
- /**
- *
- */
- private static final long serialVersionUID = -6371005564069606650L;
- @Id
- @GeneratedValue
- private Long id;
- private String stuId;
- private String stuName;
- @ManyToOne
- @JoinColumn(name="majorId")
- private MajorInfo majorInfo;
- public Long getId() {
- return id;
- }
- public void setId(Long id) {
- this.id = id;
- }
- public String getStuId() {
- return stuId;
- }
- public void setStuId(String stuId) {
- this.stuId = stuId;
- }
- public String getStuName() {
- return stuName;
- }
- public void setStuName(String stuName) {
- this.stuName = stuName;
- }
- public MajorInfo getMajorInfo() {
- return majorInfo;
- }
- public void setMajorInfo(MajorInfo majorInfo) {
- this.majorInfo = majorInfo;
- }
- }
majorInfo表的POJO:
- package pojo;
- import java.io.Serializable;
- import javax.persistence.Entity;
- import javax.persistence.GeneratedValue;
- import javax.persistence.Id;
- import org.hibernate.validator.constraints.Length;
- import org.hibernate.validator.constraints.NotEmpty;
- @Entity
- public class MajorInfo implements Serializable{
- /**
- *
- */
- private static final long serialVersionUID = 6367248158160032489L;
- @Id
- @GeneratedValue
- private Long id;
- @NotEmpty
- @Length(min=5, max=5)
- private String majorId;
- @Length(max=15)
- private String majorName;
- public Long getId() {
- return id;
- }
- public void setId(Long id) {
- this.id = id;
- }
- public String getMajorId() {
- return majorId;
- }
- public void setMajorId(String majorId) {
- this.majorId = majorId;
- }
- public String getMajorName() {
- return majorName;
- }
- public void setMajorName(String majorName) {
- this.majorName = majorName;
- }
- }
當我查詢的學生信息的時候,控制檯輸出了錯誤,內容如下:
Unable to find pojo.MajorInfo with id 301
是這樣的,我要顯示的是數據庫中第一條記錄,然而stuInfo表中第一條記錄majorID字段存儲的是0301,根據提示信息,JPA自動對應的是majorInfo表中的id字段。而且把字符串varchar類型的數據”0301“自動轉換成了”301“,然而majorInfo表中的數據沒有id爲301的記錄,因此當然在關聯majorInfo表記錄時產生了空指向異常從而報錯。問題的癥結在於在StuInfo類中,指明瞭majorInfo屬性綁定到"majorId"列,但JPA自動建立的關聯目標是從表majorInfo的索引列id,這樣一來難怪會出問題。
後來查閱資料,發現在StuInfo類中的majorInfo屬性註解配置有問題。@JoinColumn註解的name參數只是綁定該POJO映射到表的某一列的列名,並不影響從表綁定列名,如果沒有其他特別指示,JPA會自動與從表的主鍵進行關聯。解決問題的代碼就是修改這個註解爲@JoinColumn(name="majorId", referencedColumnName="majorId")
這樣主表的映射列與從表的映射列都特別指定了,這時候再查詢,故障消失。
說了這麼多,其實有含金量的就一句話:@JoinColumn(name="majorId", referencedColumnName="majorId")