devstory

Référence Java Hibernate

1- Introduction

Ceci est un document de référence sur certains problèmes liés à Hibernate. Vous devriez prévisualiser le document ci-dessous pour une référence facile:

2- Téléchargement les bibliothèques qui contrôlent certaines bases de données

Lorsque vous travaillez sur une base de données, vous devez disposer d'une bibliothèque pour la contrôler.
  • Oracle
  • MySQL
  • SQLServer
  • HSQL
  • ....
Voir plus :
Nous avons le résultat :

3- La configuration Hibernate sur différente base de données

3.1- La configuration de Hibernate pour Oracle.

Tout d'abord, vous devez déclarer la bibliothèque contrôlant la base de données Oracle (comme l'instruction ci-dessus).
La configuration de Hibernate:
hibernate.cfg.xml (Oracle)
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
                     "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
                      "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
<session-factory>
<!-- Database connection settings -->
<property name="connection.driver_class">oracle.jdbc.driver.OracleDriver</property>  
<property name="connection.url">jdbc:oracle:thin:@localhost:1521:db11g</property>    
<property name="connection.username">simplehr</property>
<property name="connection.password">1234</property>


<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">2</property>

<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.Oracle10gDialect</property>

<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>


<!-- Disable the second-level cache -->
<property name="cache.provider_class">org.hibernate.cache.internal.NoCacheProvider</property>

<!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property>
<property name="hibernate.hbm2ddl.auto">create-drop</property>


 <mapping class="org.o7planning.tutorial.hibernate.entities.Department" />
 <mapping class="org.o7planning.tutorial.hibernate.entities.Employee" />
 <mapping class="org.o7planning.tutorial.hibernate.entities.SalaryGrade" />
 <mapping class="org.o7planning.tutorial.hibernate.entities.Timekeeper" />

</session-factory>
</hibernate-configuration>

3.2- La configuration de Hibernate pour MySQL

Tout d'abord, vous devez déclarer la bibliothèque contrôlant la base de données MySQL (comme l'instruction ci-dessus).
La configuration de Hibernate
hibernate.cfg.xml (MySQL)
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
<session-factory>
 <!-- Database connection settings -->
 <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
 <property name="connection.url">jdbc:mysql://tran-vmware:3306/simplehr</property>
 <property name="connection.username">root</property>
 <property name="connection.password">1234</property>

 <!-- JDBC connection pool (use the built-in) -->
 <property name="connection.pool_size">1</property>

 <!-- SQL dialect -->
 <property name="dialect">org.hibernate.dialect.MySQLDialect</property>

 <!-- Enable Hibernate's automatic session context management -->
 <property name="current_session_context_class">thread</property>

 <!-- Disable the second-level cache  -->
 <property name="cache.provider_class">org.hibernate.cache.internal.NoCacheProvider</property>

 <!-- Echo all executed SQL to stdout -->
 <property name="show_sql">true</property>

  <mapping class="org.o7planning.tutorial.hibernate.entities.Department" />
  <mapping class="org.o7planning.tutorial.hibernate.entities.Employee" />
  <mapping class="org.o7planning.tutorial.hibernate.entities.SalaryGrade" />
  <mapping class="org.o7planning.tutorial.hibernate.entities.Timekeeper" />

</session-factory>
</hibernate-configuration>

3.3- La configuration de Hibernate pour SQL Server

Tout d'abord, vous devez déclarer la bibliothèque des pilotes de base de données SQL Server (comme les instructions ci-dessus).
La configuration de Hibernate (Utiliser la bibliothèque JTDS)
hibernate.cfg.xml (SQL Server)
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
     "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
     "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
<session-factory>
  <!-- Database connection settings -->
  <property name="connection.driver_class">net.sourceforge.jtds.jdbc.Driver</property>
  <property name="connection.url">jdbc:jtds:sqlserver://localhost:1433/simplehr;instance=SQLEXPRESS</property>
  <property name="connection.username">sa</property>
  <property name="connection.password">1234</property>

  <!-- JDBC connection pool (use the built-in) -->
  <property name="connection.pool_size">1</property>

  <!-- SQL dialect -->
  <property name="dialect">org.hibernate.dialect.SQLServerDialect</property>

  <!-- Enable Hibernate's automatic session context management -->
  <property name="current_session_context_class">thread</property>

  <!-- Disable the second-level cache  -->
  <property name="cache.provider_class">org.hibernate.cache.internal.NoCacheProvider</property>

  <!-- Echo all executed SQL to stdout -->
  <property name="show_sql">true</property>

   <mapping class="org.o7planning.tutorial.hibernate.entities.Department" />
   <mapping class="org.o7planning.tutorial.hibernate.entities.Employee" />
   <mapping class="org.o7planning.tutorial.hibernate.entities.SalaryGrade" />
   <mapping class="org.o7planning.tutorial.hibernate.entities.Timekeeper" />

</session-factory>
</hibernate-configuration>

4- Hibernate & Java Persistence Annotation

Hibernate utilise des Annotation en but de décrire des informations pour une Entity. Il peut également utiliser des annotations dans la API de Hibernate situé au package org.hibernate.annotations. Il peut ainsi utiliser des Annotation dans le package javax.persistence de Java Persistence API. En en effet, les Annotations de Java Persistence API sont plus préférées.

Dans cette section, je fais une liste des annotations les plus courantes de Java Persistence API  impliquées dans l'annotation de Entity.

4.1- @Entity

@Entity sert à annoter une classe qui est une Entity.
// Phần tử (element) name của @Entity là không bắt buộc.
// Việc chỉ định rõ name của @Entity cho phép viết ngắn câu HSQL

@Entity
@Table(name = "ACCOUNT")
public class Account implements Serializable {
    
}

// Phần tử (element) name của @Entity là không bắt buộc.
// Entity khớp với một bảng lấy theo tên theo thứ tự ưu tiên:
//  1 - name trong @Table
//  2 - name trong @Entity
//  3 - name của class.
// Việc chỉ định rõ name của @Entity cho phép viết ngắn câu HSQL

@Entity(name="AccTransaction")
@Table(name = "ACC_TRANSACTION")
public class AccTransaction implements Serializable {

}
 
L'indication le name de @Entity vous aide à raccourcir l'instruction HSQL. Veuillez observer l'illustration :
// @Entity chú thích trên class Account không chỉ định rõ phần tử name.
// Vì vậy câu HSQL bắt buộc phải viết:

String hsql1 = "Select o from "+ Account.class.getName() +" o ";


// @Entity chú thích trên class AccTransaction
// chỉ định rõ phần tử name = "AccTransaction"
// Vì vậy câu HSQL có thể viết ngắn gọn:

String hsql2 = "Select o from AccTransaction o";

4.2- @Table

Un Table dans la base de données peut avoir plusieurs contraintes uniques. @Table vous permet également de l'annoter.
// @Table cho phép chú thích tên bảng
// Các giàng buộc duy nhất trong bảng.
// Phần tử name không bắt buộc.
// Nếu bạn không chỉ rõ tên bảng trong phần tử name ...
// .. Hibernate sẽ dựa vào phần tử name của @Entity sau đó mới
// tới tên của class.

@Table( name = "invoice_header",
           uniqueConstraints = @UniqueConstraint(columnNames ={ "invoice_num" }   )
)
@Entity
public class InvoiceHeader  implements java.io.Serializable {

       private String invoiceNum;


      @Column(name = "invoice_num", nullable = false, length = 20)
      public String getInvoiceNum() {
          return this.invoiceNum;
      }

}

4.3- @Id

Par exemple @Id participe à l'annotation ID (Identity) de Entity, ce qui équivaut à la compréhension que cette colonne est la clé primaire (Primary Key) du tableau.
@Entity
@Table(name = "EMPLOYEE")
public class Employee implements Serializable {

    private Integer empId;

    // @Id chú thích đây là id của Entity.
    // Và EMP_ID chính là khóa chính (Primary Key) của bảng.

    @Id
    @GeneratedValue
    @Column(name = "EMP_ID")
    public Integer getEmpId() {
        return empId;
    }

     ......
}

4.4- @GeneratedValue

@Target({METHOD, FIELD})
@Retention(RUNTIME)
public @interface GeneratedValue {

  // GenerationType: AUTO, TABLE, SEQUENCE, IDENTITY
  GenerationType strategy() default AUTO;

  String generator() default "";

}
@GeneratedValue est annotée pour que Hibernate énère automatiquement une valeur et  lui attribue une colonne dans le cas de insert une nouvelle Entity à la base de données. Il peut être monté sur une colonne ID ou une colonne.

Parfois, il est également annoté avec @Generator

4.4.1- GenerationType.AUTO

// Chú thích @GeneratedValue tương đương với
// @GeneratedValue(strategy=GenerationType.AUTO)

@GeneratedValue
@Id
@Column(name = "EMP_ID")
public Integer getEmpId() {
    return empId;
}
La colonne annotée par @GeneratedValue(strategy= AUTO) sera affectée une valeur automatique, cette valeur peut être générée par SEQUENCE ou augmenter par elle-même (si cette colonne est de type IDENTITY). Cela dépend du type de DB.
Avec Oracle, Postgres, Hibernate appelera une Sequence baptisée Hibernate_Sequence pour créer une valeur incrémentale pour assigner des valeurs à cette colonne. Avec d'autres DB telles que MySQL, DB2, SQL Server, Sysbase la colonne peut être du type IDENTITY et sa valeur peut augmenter elle-même.

4.4.2- GenerationType.IDENTITY

La colonne qui est du type IDENTITY est soutenue par certaines bases de données mais pas toutes, par exemple MySQL, DB2, SQL Server, SybasePostgres. Oracle ne soutiennent pas une colonne comme celle-ci.
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Id
@Column(name = "EMP_ID")
public Integer getEmpId() {
   return empId;
}

4.4.3- GenerationType.SEQUENCE

SEQUENCE est un objet dans une base de données, stockant une valeur progressive après chaque appel pour obtenir la valeur suivante, et est soutenu par Oracle, DB2, et Postgres.
@GeneratedValue(strategy=GenerationType.SEQUENCE)
@Id
@Column(name = "EMP_ID")
public Integer getEmpId() {
   return empId;
}

4.4.4- GenerationType.TABLE

@Entity
public class Employee {
    ...
    @TableGenerator(
        name="empGen",
        table="ID_GEN_TABLE",
        pkColumnName="KEY_COLUMN",
        valueColumnName="VALUE_COLUMN",
        pkColumnValue="EMP_ID",
        allocationSize=1)
    @Id
    @GeneratedValue(strategy=TABLE, generator="empGen")
    public Long getEmpId()  {
       return empId;
    }
    ...
}


@Entity
public class Department {
    ...
    @TableGenerator(
        name="deptGen",
        table="ID_GEN_TABLE",
        pkColumnName="KEY_COLUMN",
        valueColumnName="VALUE_COLUMN",
        pkColumnValue="DEPT_ID",
        allocationSize=1)
    @Id
    @GeneratedValue(strategy=TABLE, generator="deptGen")
    public Long getDeptId()  {
       return deptId;
    }
    ...
}
 

Remarque : Vous pouvez personnaliser le nom du tableau et le nom de la colonne (ID_GEN_TABLE, KEY_COLUMN, VALUE_COLUMN)

4.4.5- UUID

UUID est une classe de Java qui vous permet de créer une chaîne aléatoire de 36 caractères. Et avec 36 caractères, la probabilité identique est extrêmement faible.

Vous pouvez également annoter afin que le Hibernate génère une chaîne aléatoire de ce type affectée à la valeur de la colonne.
 // Sử dụng strategy = "uuid2".

@GenericGenerator(name="my-uuid", strategy = "uuid2")
@GeneratedValue(generator="my-uuid")
@Id
@Column(name = "EMP_ID", length = 36)
public String getEmpId()  {
   return empId;
}

4.5- @Column

@Column annote une colonne, y compris les informations sur la longueur de la colonne, autorisant null ou non.
// Đây là một cột kiểu chuỗi, vì thế length luôn có ý nghĩa và cần thiết
// nullable mặc định là true
// length mặc định là 255

@Column(name = "FIRST_NAME", length = 20, nullable = false)
public String getFirstName() {
    return firstName;
}


// @Column không chỉ rõ phần tử length, mặc định nó là 255.

@Column(name = "DESCRIPTION", nullable = true )
public String getDescription() {
    return firstName;
}

// Với các cột kiểu số hoặc Date bạn có thể bỏ qua length
// (Nó không có ý nghĩa trong trường hợp này).

@Column(name = "PENDING_BALANCE")
public Float getPendingBalance() {
    return pendingBalance;
}




 

4.6- @Lob

@Lob sont généralement annotée avec @Column pour informer que ladite colonne est du type BLOB ou CLOB.
// Chú ý rằng trong một số Database có phân biệt TINY, MEDIUM, LARGE BLOB/CLOB.
// Còn một số database thì không.
// Phần tử length trong @Column trong trường hợp này sẽ quyết định nó map
// vào BLOB/CLOB nào.
// Trong trường hợp cho phép BLOB/CLOB tối đa hãy để length = Integer.MAX_VALUE


// Method này trả về byte[]
// @Lob trong trường hợp này chú thích cho cột BLOB

@Lob
@Column(name = "IMAGE_VALUE", nullable = true, length = Integer.MAX_VALUE)
public byte[] getImageValue() {
    this.imageValue;
}

// Method này trả về String
// @Lob trong trường hợp này sẽ chú thích cho CLOB.

@Lob
@Column(name = "ARTICLE_CONTENT", nullable = true, length = Integer.MAX_VALUE)
public String getArticleContent() {
    this.articleContent;
}

4.7- @Temporal

@Temporal sert à annoter la colonne de données telles que la date, le jour, le mois et l'heure (date time).
// @Temporal sử dụng chú thích cho cột có kiểu dữ liệu ngày tháng.
// Có 3 giá trị cho TemporalType:
// 1 - TemporalType.DATE
// 2 - TemporalType.TIME
// 3 - TemporalType.TIMESTAMP

@Temporal(TemporalType.DATE)
@Column(name = "START_DATE", nullable = false)
public java.util.Date getStartDate() {
    return startDate;
}

// TemporalType.DATE chú thích cột sẽ lưu trữ ngày tháng năm (bỏ đi thời gian)
// TemporalType.TIME chú thích cột sẽ lưu trữ thời gian (Giờ phút giây)
// TemporalType.TIMESTAMP chú thích cột sẽ lưu trữ ngày tháng và cả thời gian

@Temporal(TemporalType.TIMESTAMP)
@Column(name = "FUNDS_AVAIL_DATE", nullable = false)
public java.util.Date getFundsAvailDate() {
      return fundsAvailDate;
}

4.8- @ManyToOne

@ManyToOne décrit une relation  N-1 (Plusieur - une), qui est fréquemment utilisé avec @JoinColumn.
@Entity
@Table(name = "ACCOUNT")
public class Account implements Serializable {

 
    private Branch openBranch;
 
   // Phần tử foreignKey giúp chỉ rõ tên Foreign Key trong DB.
   // Điều này sẽ giúp Hibernate tạo ra DB từ các Entity java một cách chính xác hơn.

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "OPEN_BRANCH_ID", nullable = false,
                 foreignKey = @ForeignKey(name = "ACCOUNT_BRANCH_FK"))
    public Branch getOpenBranch() {
        return openBranch;
    }

}
Hibernate possède les outils qui vous permettent de gérer des classes Entity du tableau dans la base de données. Et Hibernate vous permet également de générer un tableau à partir des classes Entity, y compris des contraintes entres des tableaux (Foreign Key). L'annotation @ForeignKey permet d'indiquer aye le nom Foreign Key sera créé.
@ForeignKey est introduit dans JPA de la version 2.1
// Phần tử fetch có 2 giá trị
// 1 - FetchType.LAZY
// 2 - FetchType.EAGER

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "OPEN_BRANCH_ID", nullable = false,
             foreignKey = @ForeignKey(name = "ACCOUNT_BRANCH_FK"))
public Branch getOpenBranch() {
    return openBranch;
}

LAZY:

LAZY annonce à Hibernate que "veuillez charger des données paresseusement".
Par exemple, vous avez un objet Account et vous appelez la méthode getOpenBranch(). Elle renvoie un objet Branch, dans cet objet Branch , seul champ (field) branchId est affectué une valeur alors que les autres ne sont pas les mêmes.

En effet hibernate ne charge pas de données de l'enregistrement correspondant du tableau BRANCH au cet objet. Hibernate n'effectue que des données lors que vous faites quelque chose avec l'objet Branch que vous avez récemment obtenu, par exemple l'appel de la méthode branch.getName().

EAGER:

EAGER demande à Hibernate d'interroger toutes les colonnes du tableau concerné.
Par exemple, vous avez un objet Account et vous appelez la méthode getOpenBranch(). Cette méthode renvoie l'objet Branch qui ont des valeurs disponibles pour les champs (name, address, ...). En effet, ses données sont acquis dans une même requête avec le tableau Account.
Vous devriez utiliser LAZY au lieu d'utiliser EAGER à cause des raisons de performance du programme.

4.9- @OneToMany

@OneToMany est  l'annotation pour récupérer une liste des sous enregistrement de l'enregistrement en cours (Ceci est une relation multiple). C'est l'inverse de l'annotation @ManyToOne, et par conséquent, il se base sur l'annotation  @ManyToOne pour donner la définition de @OneToMany.
@Entity
@Table(name = "EMPLOYEE")
public class Employee implements Serializable {

    ....

    private Department department;
 
    // Quan hệ N-1 (Nhiều - Một) định nghĩa department.   

    @JoinColumn(name = "DEPT_ID", nullable = true,
              foreignKey = @ForeignKey(name = "EMPLOYEE_DEPARTMENT_FK"))    
    @ManyToOne(fetch = FetchType.LAZY)    
    public Department getDepartment() {
        return department;
    }
 

}



@Entity
@Table(name = "DEPARTMENT")
public class Department implements Serializable {

        .....

    private Set<Employee> employees = new HashSet<Employee>(0);

    // Quan hệ 1-N (Một - Nhiều) sử dụng mappedBy = "department"
    // đã định nghĩa ở quan hệ N-1 (phía trên).

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "department")
    public Set<Employee> getEmployees() {
        return employees;
    }
}

4.10- @OrderBy

@OrderBy sert à arranger une collection, donc elle peut être combinée avec @OneToMany:

@Entity
@Table(name = "DEPARTMENT")
public class Department implements Serializable {

        .....

    private Set<Employee> employees = new HashSet<Employee>(0);

    // Mặc định @OrderBy("empNo") tương đương với @OrderBy("empNo asc").
    // Nó tạo ra câu SQL: Select ... from Employee ... order by EMP_NO desc

    @OrderBy("empNo desc")
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "department")
    public Set<Employee> getEmployees() {
        return employees;
    }
}

4.11- @Transient

Observez quelques case ci-dessous :
@Entity
@Table(name="Employee")
public class Employee implements Serializable {
 
      .....

      @Column(name="FIRST_NAME", nullable =false , length = 20 )
      public String getFirstName()  {
           return this.firstName;
      }

      @Column(name="LAST_NAME", nullable =false , length = 20)
      public String getLastName()  {
           return this.lastName;
      }

     public String getFullName()  {
          return this.firstName+ " "+ this.lastName;
     }
}
Vous voulez écrire une méthode getFullName(). Cette méthode qui est uniquement un calcul, non liée à une colonne sous la DB. Par conséquent, vous devez utiliser @Transient pour notifier votre intention de Hibernate.
@Transient
public String getFullName()  {
     return this.firstName+ " " + this.lastName;
}

@Transient
public boolean isManagerEmployee()  {
      return this.manager != null;
}

4.12- @Inheritance