第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

Hibernate 中主鍵映射的助攻

1. 前言

本節(jié)課和大家一起聊聊 Hibernate 中的主鍵策略。通過(guò)本節(jié)課程,你將了解到:

  • 什么是主鍵策略及主鍵生成器的種類;
  • 如何映射復(fù)合主鍵。

2. 主鍵策略

Hibernate 進(jìn)行數(shù)據(jù)庫(kù)操作時(shí),可依靠主鍵生成器組件更快速、準(zhǔn)確地進(jìn)行一系列操作。這便是主鍵策略

2.1 主鍵生成器

主鍵是關(guān)系數(shù)據(jù)庫(kù)中的概念,目的是唯一標(biāo)識(shí)表中記錄,保證實(shí)體數(shù)據(jù)的完整性。

  • 關(guān)系數(shù)據(jù)庫(kù)中表與表中數(shù)據(jù)的關(guān)系描述需依賴主鍵實(shí)現(xiàn) ;
  • 另有外鍵概念,所謂外鍵是在另一張表中對(duì)引用表的主鍵值的引用稱呼。

主外鍵關(guān)系指在不同的表中通過(guò)共同的字段信息建立起表中數(shù)據(jù)依賴(引用)關(guān)系。

回到 Hibernate 的世界!先展示一段代碼:

Student student = new Student(2, "Configuration老二", "男");
session.save(student);

上面的代碼功能:把應(yīng)用程序中的數(shù)據(jù)寫入到數(shù)據(jù)庫(kù)中,沒(méi)毛病呀!

來(lái)!沒(méi)毛病找點(diǎn)毛病出來(lái):

實(shí)際操作時(shí),要求 Hibernate 把程序中 stuId 屬性的值插入到表中同名的 stuId 主鍵字段中。

主鍵有什么特點(diǎn)?

唯一性!回答得對(duì)。

請(qǐng)問(wèn)在應(yīng)用程序中構(gòu)建數(shù)據(jù)時(shí),如何確保賦值給 stuId 的值在表中不存在!這就是問(wèn)題所在。

如何解決?

使用 Hibernate 主鍵生成器。

所謂主鍵生成器其作用就是在 Hibernate 向表中插入數(shù)據(jù)時(shí),負(fù)責(zé)生成表中數(shù)據(jù)記錄的主鍵。

Hibernate 主鍵生成器 API 介紹:

  • Hibernate 的主鍵生成器(generator)都實(shí)現(xiàn)了 org.hibernate.id.IdentityGenerator 接口;
 public class IdentityGenerator extends AbstractPostInsertGenerator { …… }
  • 開(kāi)發(fā)者可以遵循這個(gè)接口規(guī)范提供自己的主鍵生成方案;
  • Hibernate 內(nèi)置有較多主鍵生成器主鍵生成器都有自己的實(shí)現(xiàn)類,并提供有快捷名稱方便在注解或 XML 中引用。

常用主鍵生成器一覽:

  • org.hibernate.id.IncrementGenerator(increment):對(duì) long、shortint 的數(shù)據(jù)列生成自動(dòng)增長(zhǎng)主鍵;

  • org.hibernate.id.IdentityGeneratoridentity): 適用于 SQL server,MySql 等支持自動(dòng)增長(zhǎng)列的數(shù)據(jù)庫(kù),適合 long、shortint 數(shù)據(jù)列類型;

  • org.hibernate.id.SequenceGeneratorsequecne):適用 oracle,DB2 等支持 Sequence 的數(shù)據(jù)庫(kù),適合 long、shortint 數(shù)據(jù)列類型;

  • org.hibernate.id.UUIDGeneratoruuid):對(duì)字符串列的數(shù)據(jù)采用 128 - 位 uuid 算法生成唯一的字符串主鍵;

  • org.hibernate.id.Assigned(assigned):由應(yīng)用程序指定,也是默認(rèn)生成策略。

默認(rèn)使用 assigned 生成器。這種方案要求開(kāi)發(fā)者在應(yīng)用程序中提供自己的主鍵生成算法:

  • 調(diào)用保存方法之前,先帶著指定的值往數(shù)據(jù)庫(kù)中跑一趟,檢索是否存在重復(fù),如果有,再試其它值;
  • 調(diào)用保存方法之前,先檢索到表中 stuId 字段值的最大值,返回應(yīng)用程序后遞增 1,用于 stuId 新值。如果多個(gè)用戶同時(shí)向數(shù)據(jù)中插入數(shù)據(jù),這種方案會(huì)出問(wèn)題,不適合并發(fā)操作環(huán)境。

使用 assigned 生成器除非有一個(gè)很完美的解決方案,否則建議只用于學(xué)習(xí)或測(cè)試環(huán)境。

本課程使用的是 Mysql 數(shù)據(jù)庫(kù),最佳選擇 identity 生成器,主鍵值交給數(shù)據(jù)庫(kù)的自動(dòng)增長(zhǎng)列自動(dòng)生成。

2.2 使用主鍵生成器重構(gòu)代碼

  1. 在 Student 類的標(biāo)識(shí)屬性(stuId)上標(biāo)注如下注解;
 @Id
 @GeneratedValue(strategy=GenerationType.IDENTITY)
 public Integer getStuId() {
     return stuId;
 }

簡(jiǎn)單得難以置信!空靈而干凈??!

使用 @GeneratedValue 注解確定主鍵生成器類型。GenerationType 是一個(gè)枚舉類型,有如下幾個(gè)選擇:

  • AUTOHibernate 區(qū)分?jǐn)?shù)據(jù)庫(kù)系統(tǒng),自動(dòng)選擇最佳策略;
  • IDENTITY: 適合具有自動(dòng)增長(zhǎng)類型的數(shù)據(jù)庫(kù),如 MySql……
  • SEQUENCE: 適合如 Oracle 類型數(shù)據(jù)庫(kù);
  • TABLE: 使用 Hibernate 提供的 TableGenerator 生成器,不常用。
  1. 為了更好觀察生成的新數(shù)據(jù),重建數(shù)據(jù)庫(kù)中的表。主配置文件中修改或添加如下配置信息;
 <property name="hbm2ddl.auto">create</property>
  1. 執(zhí)行插入數(shù)據(jù)實(shí)例;
  // 打開(kāi)事務(wù)
  try{
      transaction = session.beginTransaction();
      // 添加一條學(xué)生信息,此處沒(méi)有指定學(xué)生編號(hào)
      Student student = new Student("Hibernate 01", "男");
      session.save(student);
      transaction.commit();  
  } catch(Exception e) {
      transaction.rollback(); 
  } finally {
      session.close();
  }
  1. 進(jìn)入 Mysql 系統(tǒng)查看,表結(jié)構(gòu)中 stuId 自動(dòng)設(shè)為主鍵,且為自動(dòng)遞增;
    圖片描述

  2. 查看表中數(shù)據(jù),主鍵值自動(dòng)生成;

  3. 試著多加幾條數(shù)據(jù),別忘記修改如下配置信息。

 <property name="hbm2ddl.auto">update</property>

圖片描述

大功告成??!

2.3 主鍵生成器

使用注解 @GeneratedValue 指定生成器類型后,Hibernate 一般情況下會(huì)自動(dòng)創(chuàng)建對(duì)應(yīng)的生成器對(duì)象,如前面指定類型為 IDENTITY,則創(chuàng)建生成 org.hibernate.id.IdentityGenerator 對(duì)象。

如果需要個(gè)性化定制生成器對(duì)象,則需要顯示指定生成器對(duì)象,如為 Oracle 數(shù)據(jù)庫(kù)指定主鍵生成器時(shí),則配置可如下:

XML 映射方式:

<id name="stuId" type="Integer" column="stuId">
    <generator class="sequence">
        <param name="sequence">mySeq</param>
    </generator>
</id>

注解映射方式:

@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE,generator="mySeqIdGen")
@SequenceGenerator(name="mySeqIdGen",sequenceName="mySeq")
public Integer getStuId() {
    return stuId;
}

@SequenceGenerator 注解顯示指明使用 org.hibernate.id.SequenceGenerator 生成器對(duì)象,并指定使用數(shù)據(jù)庫(kù)中的命名為 mySeq 的序列化器。

其它主鍵生成器的使用本文不再?gòu)?fù)述,拋磚引玉,學(xué)習(xí)者可自行深入!

3. 復(fù)合主鍵

3.1 什么是復(fù)合主鍵

關(guān)系數(shù)據(jù)庫(kù)中,主鍵可指定一個(gè)字段實(shí)現(xiàn),也可指定多個(gè)字段實(shí)現(xiàn),這樣的主鍵叫復(fù)合主鍵。

從數(shù)據(jù)庫(kù)表設(shè)計(jì)原則分析,盡可能少用復(fù)合主鍵,但并不排除需要使用的場(chǎng)景。

對(duì)使用 Hibernate 的開(kāi)發(fā)者而言,將面對(duì)一個(gè)新問(wèn)題:在應(yīng)用程序中,如何映射表中的復(fù)合主鍵?

應(yīng)用程序中,復(fù)合主鍵映射方案有三:

  • 嵌入類注解為 @Embeddable,并將實(shí)體類的屬性注解為 @Id;
  • 實(shí)體類的屬性注解為 @EmbeddedId;
  • 實(shí)體類注解為 @IdClass,并將該實(shí)體類所有屬于主鍵的屬性都注解為 @Id

先分清楚兩個(gè)概念:

  • 實(shí)體類:使用 @entity 注解的類;
  • 嵌入類:使用 @Embeddable 注解的類;

3.2 復(fù)合主鍵映射方案一

實(shí)施流程

  1. 假設(shè)學(xué)生表中使用了 stuId,stuName 兩字段構(gòu)成復(fù)合主鍵;

  2. 應(yīng)用程序中構(gòu)建兩個(gè)類;

    嵌入類

 @Embeddable  
 public class StudentId {
     private Integer stuId;
     private String stuName;
     public StudentId()  {
         super();
     }      
     public  StudentId(Integer stuId, String stuName) {
         super();
         this.stuId = stuId;  
         this.stuName = stuName;
     }      
    //……省略get、set方法

嵌入類說(shuō)明:

  • 標(biāo)注有 @Embeddable;

  • 類中包括 stuId、stuName 兩個(gè)屬性與表中的復(fù)合字段相呼應(yīng);

  • 必須實(shí)現(xiàn) Serializable?。?!后續(xù)章節(jié)會(huì)聊到為什么。

實(shí)體類:

  @Entity  
  public class Student_ {
      private StudentId studentId;
      private String stuSex;
      public Student_() {
          super();
      }      
      public  Student_(StudentId studentId, String stuSex) {
          super();
          this.studentId = studentId;
          this.stuSex = stuSex;
      }      
      @Id      
      public StudentId  getStudentId() {
          return studentId;
      }      
      //……省略其它set、get方法

實(shí)體類說(shuō)明:

實(shí)體類使用 @Entity 注解;
關(guān)鍵代碼分析:

關(guān)鍵點(diǎn)一: 內(nèi)部添加引用嵌入類屬性。

     private StudentId studentId;

關(guān)鍵點(diǎn)二: studentId 屬性上需要添加 @Id 注解。

    @Id
    public StudentId getStudentId() {
        return studentId;
    }
  1. 重新創(chuàng)建數(shù)據(jù)庫(kù)中的學(xué)生表:
   <property name="hbm2ddl.auto">create</property>
  1. 運(yùn)行測(cè)試實(shí)例。

    Tips: 對(duì)于復(fù)合主鍵,需要在代碼級(jí)別指定值。

   // 打開(kāi)事務(wù) 
   transaction = session.beginTransaction();
   // 添加一條學(xué)生信息 
   Student_ student = new Student_();
   // 復(fù)合主鍵信息
   StudentId studentId=new StudentId(1, "Hibernate是老大");
   student.setStudentId(studentId);
   student.setStuSex("男");
   session.save(student);
   transaction.commit();
  1. 查看 MySql,會(huì)發(fā)現(xiàn)新表 student_ 中指定復(fù)合主鍵,且數(shù)據(jù)添加成功。

圖片描述

如上所述,嵌入類就是復(fù)合主鍵映射類!

3.3 復(fù)合主鍵映射方案二

與第一方案相比,保留 @Entity 注解的實(shí)體類。

第一方案中的嵌入類上不再使用 @Embedded 注解,嵌入類降維成普通類。

實(shí)體類中不再使用 @Id 注解,而是使用 @EmbeddedId,此注解語(yǔ)義明確:一注解承擔(dān)兩注解任務(wù)。

可理解 @EmbeddedId 注解是 @Embedded@Id 兩個(gè)注解的綜合體。

@EmbeddedId
public StudentId getStudentId() {
    return studentId;
}

和第一方案一樣進(jìn)行代碼測(cè)試,結(jié)果沒(méi)什么不一樣。

3.4 復(fù)合主鍵映射方案三

方案三與前兩個(gè)方案區(qū)別:

  1. 沒(méi)有嵌入類概念,前面的嵌入類降維成一個(gè)普通類,不加任何注解描述;

此類的作用僅僅在邏輯上把兩個(gè)標(biāo)識(shí)屬性歸為一組!

 public  class StudentId implements Serializable{
     private Integer stuId;    
     private String stuName;
     public StudentId() {
         super();
     }    
     public StudentId(Integer stuId, String stuName) {
         super();
         this.stuId = stuId;
         this.stuName = stuName; 
     }    
    //……省略set、get方法
  1. 實(shí)體類中使用 @IdClass 指定內(nèi)部有標(biāo)識(shí)屬性的類,另在實(shí)體類中也重復(fù)出現(xiàn)標(biāo)識(shí)屬性且上面使用 @Id 注解。
@Entity
//指明實(shí)體類中標(biāo)注有 @Id 的屬性為同一類型
@IdClass(StudentId.class)
public class Student_ {
    private Integer stuId;
    private String stuName;
    private String stuSex;
    public Student_() {
        super();
    }
    public Student_(Integer stuId, String stuName, String stuSex) {
        super();
        this.stuId = stuId;
        this.stuName = stuName;
        this.stuSex = stuSex;
    }
    @Id
    public Integer getStuId() {
        return stuId;
    }
    @Id
    public String getStuName() {
        return stuName;
    }
    //……省略set、get方法
}

測(cè)試代碼,結(jié)果和前面 2 個(gè)方案一樣。

3.5 方案比較

通過(guò)代碼的編寫過(guò)程,3 種方案優(yōu)劣比較明顯:

  • 第一種方案和第二種方案本質(zhì)上沒(méi)有太多區(qū)別,只是一個(gè)使用 @Id@Embeddable 兩個(gè)注解;一個(gè)是使用 @EmbeddedId 注解行使兩個(gè)注解的功能;
  • 顯然,第二種方案稍優(yōu)于第一方案,至少可少使用一個(gè)注解;
  • 第三種方案代碼有重復(fù)之處,與 OOP 中的重用原則相違背,請(qǐng)慎用。

4. 小結(jié)

本節(jié)課,聊到了主鍵生成器,通過(guò)主鍵生成器這個(gè)助攻手,能有效地保持主鍵的唯一性,從而保證數(shù)據(jù)的完整性。

另聊了復(fù)合主鍵,復(fù)合主鍵映射備選方案雖多,但你可只記你心中最鐘情的那個(gè)。