openplanning

Tạo ra hệ thống Bảng từ các class Entity trong Hibernate

  1. Mục tiêu của tài liệu
  2. Tạo Maven Project & Khai báo thư viện
  3. Các lớp Entity
  4. hibernate-xxx.cfg.xml
  5. Tạo ra các bảng từ các Entity

1. Mục tiêu của tài liệu

Tài liệu này được viết dựa trên:
  • Hibernate 5.2.2.Final

  • Eclipse 4.6 (MARS)

Trong tài liệu này tôi sẽ hướng dẫn bạn tạo ra hệ thống các bảng trên một cơ sở dữ liệu bất kỳ (Oracle, MySQL, SQL Server, ..) dựa trên các lớp Entity. Các bảng được tạo ra có đầy đủ các giàng buộc (Constraints) theo chỉ định trong các lớp Entity.

Hãy chú ý rằng Hibernate sinh ra để có thể làm việc với mọi cơ sở dữ liệu. Vì vậy khi chuyển sang sử dụng loại database khác bạn không phải thay đổi lại code của chương trình. Tuy nhiên bạn cần phải tạo ra hệ thống các bảng trong database. Hibernate hỗ trợ bạn tạo ra hệ thống các bảng từ các lớp Entity.
Tài liệu này là phần tiếp theo của "Hướng dẫn lập trình Hibernate cho người mới bắt đầu", mà bạn có thể xem tại đây:

2. Tạo Maven Project & Khai báo thư viện

Trong pom.xml tôi khai báo thư viện Hibernate 5, và các thư viện JDBC cho các loại Database khác nhau Oracle, MySQLSQL Server.
pom.xml
<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.o7planning</groupId>
  <artifactId>HibernateGenerateTables</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>HibernateGenerateTables</name>
  <url>http://maven.apache.org</url>


   <properties>
       <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
   </properties>


   <repositories>
       <!-- Repository for ORACLE JDBC Driver -->
       <repository>
           <id>codelds</id>
           <url>https://code.lds.org/nexus/content/groups/main-repo</url>
       </repository>
   </repositories>
 
 
   <dependencies>


       <dependency>
           <groupId>junit</groupId>
           <artifactId>junit</artifactId>
           <version>3.8.1</version>
           <scope>test</scope>
       </dependency>

       <!-- Hibernate Core -->
       <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core -->
       <dependency>
           <groupId>org.hibernate</groupId>
           <artifactId>hibernate-core</artifactId>
           <version>5.2.2.Final</version>
       </dependency>


       <!-- MySQL JDBC driver -->
       <!-- http://mvnrepository.com/artifact/mysql/mysql-connector-java -->
       <dependency>
           <groupId>mysql</groupId>
           <artifactId>mysql-connector-java</artifactId>
           <version>5.1.34</version>
       </dependency>

       <!-- Oracle JDBC driver -->
       <dependency>
           <groupId>com.oracle</groupId>
           <artifactId>ojdbc6</artifactId>
           <version>11.2.0.3</version>
       </dependency>

       <!-- SQLServer JDBC driver (JTDS) -->
       <!-- http://mvnrepository.com/artifact/net.sourceforge.jtds/jtds -->
       <dependency>
           <groupId>net.sourceforge.jtds</groupId>
           <artifactId>jtds</artifactId>
           <version>1.3.1</version>
       </dependency>

   </dependencies>
 
</project>

3. Các lớp Entity

Chúng ta tạo các lớp Entity. Mỗi Entity sẽ mô tả một bảng trong DB. Hãy khoan nói về những gì có trong các lớp đó.
  • Department - Phòng ban
  • Employee - Nhân viên
  • SalaryGrade - Bậc lương
  • Timekeeper - Máy chấm công, giờ ra vào của nhân viên.
Department.java
package org.o7planning.tutorial.hibernate.entities;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;

@Entity
@Table(name = "DEPARTMENT",
  uniqueConstraints = { @UniqueConstraint(columnNames = { "DEPT_NO" }) })
public class Department {

private Integer deptId;
private String deptNo;

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

public Department() {
}

public Department(Integer deptId, String deptName, String location) {
   this.deptId = deptId;
   this.deptNo = "D" + this.deptId;
   this.deptName = deptName;
   this.location = location;
}

@Id
@Column(name = "DEPT_ID")
public Integer getDeptId() {
   return deptId;
}

public void setDeptId(Integer deptId) {
   this.deptId = deptId;
}

@Column(name = "DEPT_NO", length = 20, nullable = false)
public String getDeptNo() {
   return deptNo;
}

public void setDeptNo(String deptNo) {
   this.deptNo = deptNo;
}

@Column(name = "DEPT_NAME", nullable = false)
public String getDeptName() {
   return deptName;
}

public void setDeptName(String deptName) {
   this.deptName = deptName;
}

@Column(name = "LOCATION")
public String getLocation() {
   return location;
}

public void setLocation(String location) {
   this.location = location;
}

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

public void setEmployees(Set<Employee> employees) {
   this.employees = employees;
}
}
Employee.java
package org.o7planning.tutorial.hibernate.entities;

import java.util.Date;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.Lob;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.UniqueConstraint;

@Entity
@Table(name = "EMPLOYEE",
   uniqueConstraints = { @UniqueConstraint(columnNames = { "EMP_NO" }) })
public class Employee {
private Long empId;
private String empNo;

private String empName;
private String job;
private Employee manager;
private Date hideDate;
private Float salary;
private byte[] image;

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

public Employee() {
}

public Employee(Long empId, String empName, String job, Employee manager,
        Date hideDate, Float salary, Float comm, Department department) {
    this.empId = empId;
    this.empNo = "E" + this.empId;
    this.empName = empName;
    this.job = job;
    this.manager = manager;
    this.hideDate = hideDate;
    this.salary = salary;
    this.department = department;
}

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

public void setEmpId(Long empId) {
    this.empId = empId;
}

@Column(name = "EMP_NO", length = 20, nullable = false)
public String getEmpNo() {
    return empNo;
}

public void setEmpNo(String empNo) {
    this.empNo = empNo;
}

@Column(name = "EMP_NAME", length = 50, nullable = false)
public String getEmpName() {
    return empName;
}

public void setEmpName(String empName) {
    this.empName = empName;
}

@Column(name = "JOB", length = 30, nullable = false)
public String getJob() {
    return job;
}

public void setJob(String job) {
    this.job = job;
}

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "MNG_ID")
public Employee getManager() {
    return manager;
}

public void setManager(Employee manager) {
    this.manager = manager;
}

@Column(name = "HIRE_DATE", nullable = false)
@Temporal(TemporalType.DATE)
public Date getHideDate() {
    return hideDate;
}

public void setHideDate(Date hideDate) {
    this.hideDate = hideDate;
}

@Column(name = "SALARY", nullable = false)
public Float getSalary() {
    return salary;
}

public void setSalary(Float salary) {
    this.salary = salary;
}

@Column(name = "IMAGE", length = 1111111, nullable = true)
@Lob
public byte[] getImage() {
    return image;
}

public void setImage(byte[] image) {
    this.image = image;
}

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

public void setDepartment(Department department) {
    this.department = department;
}

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

public void setEmployees(Set<Employee> employees) {
    this.employees = employees;
}

}
SalaryGrade.java
package org.o7planning.tutorial.hibernate.entities;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "SALARY_GRADE")
public class SalaryGrade {
 private Integer grade;
 private Float lowSalary;
 private Float highSalary;

 public SalaryGrade() {
 }

 public SalaryGrade(Integer grade, Float lowSalary, Float highSalary) {
     this.grade = grade;
     this.lowSalary = lowSalary;
     this.highSalary = highSalary;
 }

 @Id
 @Column(name = "GRADE")
 public Integer getGrade() {
     return grade;
 }

 public void setGrade(Integer grade) {
     this.grade = grade;
 }

 @Column(name = "LOW_SALARY", nullable = false)
 public Float getLowSalary() {
     return lowSalary;
 }

 public void setLowSalary(Float lowSalary) {
     this.lowSalary = lowSalary;
 }

 @Column(name = "HIGH_SALARY", nullable = false)
 public Float getHighSalary() {
     return highSalary;
 }

 public void setHighSalary(Float highSalary) {
     this.highSalary = highSalary;
 }
}
Timekeeper.java
package org.o7planning.tutorial.hibernate.entities;

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import org.hibernate.annotations.GenericGenerator;

@Entity
@Table(name = "TIMEKEEPER")
public class Timekeeper {
  public static final char IN = 'I';
  public static final char OUT = 'O';

  private String timekeeperId;

  private Date dateTime;

  private Employee employee;

  // 'I' or 'O'
  private char inOut;

  @Id
  @GeneratedValue(generator = "uuid")
  @GenericGenerator(name = "uuid", strategy = "uuid2")
  @Column(name = "Timekeeper_Id", length = 36)
  public String getTimekeeperId() {
      return timekeeperId;
  }

  public void setTimekeeperId(String timekeeperId) {
      this.timekeeperId = timekeeperId;
  }

  @Column(name = "Date_Time", nullable = false)
  @Temporal(TemporalType.TIMESTAMP)
  public Date getDateTime() {
      return dateTime;
  }

  public void setDateTime(Date dateTime) {
      this.dateTime = dateTime;
  }

  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "EMP_ID", nullable = false)
  public Employee getEmployee() {
      return employee;
  }

  public void setEmployee(Employee employee) {
      this.employee = employee;
  }

  @Column(name = "In_Out", nullable = false, length = 1)
  public char getInOut() {
      return inOut;
  }

  public void setInOut(char inOut) {
      this.inOut = inOut;
  }

}

4. hibernate-xxx.cfg.xml

Để tạo ra các bảng bạn cần một file cấu hình thông tin database (hibernate-<datatype>.cfg.xml) và các lớp Entity.
hibernate-oracle.cfg.xml
<?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>

       <property name="hibernate.dialect">org.hibernate.dialect.OracleDialect</property>
       <property name="hibernate.connection.driver_class">oracle.jdbc.driver.OracleDriver</property>
       <property name="hibernate.connection.url">jdbc:oracle:thin:@localhost:1521:db12c</property>
       <property name="hibernate.connection.username">simplehr2</property>
       <property name="hibernate.connection.password">12345</property>
       <property name="hibernate.show_sql">true</property>
       <property name="hibernate.connection.release_mode">auto</property>
       <property name="current_session_context_class">thread</property>
       <property name="hibernate.connection.autoReconnect">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>
hibernate-mysql.cfg.xml
<?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?serverTimezone=UTC</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>
hibernate-sqlserver.cfg.xml
<?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>
Đảm bảo rằng bạn đã tạo ra các Schema rỗng. (Các database rỗng) chưa có các bảng. Ví dụ với Oracle tôi tạo ra một Schema mới có tên simplehr2.
-- ORACLE
Create user simplehr2 identified by 12345;
grant dba to simplehr2;

5. Tạo ra các bảng từ các Entity

SchemaGeneratorDemo.java
package org.o7planning.generatetables;

import java.io.File;
import java.util.EnumSet;

import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.hibernate.tool.schema.TargetType;

// Hibernate 5.
public class SchemaGeneratorDemo {

   public static final String SCRIPT_FILE = "exportScript.sql";

   private static SchemaExport getSchemaExport() {

       SchemaExport export = new SchemaExport();
       // Script file.
       File outputFile = new File(SCRIPT_FILE);
       String outputFilePath = outputFile.getAbsolutePath();

       System.out.println("Export file: " + outputFilePath);

       export.setDelimiter(";");
       export.setOutputFile(outputFilePath);

       // Không ngừng nếu có lỗi
       export.setHaltOnError(false);
       //
       return export;
   }

   public static void dropDataBase(SchemaExport export, Metadata metadata) {

       // TargetType.DATABASE - Thực thi lệnh vào Databse
       // TargetType.SCRIPT - Ghi ra file Script.
       // TargetType.STDOUT - Ghi thông tin Log ra màn hình Console.
       EnumSet<TargetType> targetTypes = EnumSet.of(TargetType.DATABASE, TargetType.SCRIPT, TargetType.STDOUT);

       export.drop(targetTypes, metadata);
   }

   public static void createDataBase(SchemaExport export, Metadata metadata) {
 
       // TargetType.DATABASE - Thực thi lệnh vào Databse
       // TargetType.SCRIPT - Ghi ra file Script.
       // TargetType.STDOUT - Ghi thông tin Log ra màn hình Console.
       EnumSet<TargetType> targetTypes = EnumSet.of(TargetType.DATABASE, TargetType.SCRIPT, TargetType.STDOUT);

       SchemaExport.Action action = SchemaExport.Action.CREATE;
       //
       export.execute(targetTypes, action, metadata);

       System.out.println("Export OK");

   }

   public static void main(String[] args) {
       // Sử dụng Oracle.
       String configFileName = "hibernate-oracle.cfg.xml";
 
       // Tạo đối tượng ServiceRegistry từ hibernate-xxx.cfg.xml
       ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()//
               .configure(configFileName).build();
 
       // Tạo nguồn siêu dữ liệu (metadata) từ ServiceRegistry
       Metadata metadata = new MetadataSources(serviceRegistry).getMetadataBuilder().build();

       SchemaExport export = getSchemaExport();

       System.out.println("Drop Database...");
       // Drop Database
       dropDataBase(export, metadata);

       System.out.println("Create Database...");
 
       // Tạo lại hệ thống bảng
       createDataBase(export, metadata);
   }
   
}
Chạy ví dụ:
Xem file Script: