Java Hibernate reference
1. Introduction
This is a reference document on some issues related to Hibernate. You should preview the document below for easy reference:
2. Downloading the libraries which control some Databases
When you work on some database, you need to have a library to control it.
- Oracle
- MySQL
- SQLServer
- HSQL
- ....
See more:
We have the result:
3. Hibernate configuration on diferent databases.
No ADS
Hibernate configuration for Oracle.
First of all, you have to declare the library controlling the Oracle database (the above instruction).
Hibernate configuration:
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>
Hibernate congiguration for MySQL
First of all, you have to declare the library controlling the MySQL database (the above instruction).
Hibernate configuration
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>
Hibernate congiguration for SQL Server
First of all, you have to declare the SQLServerdatabase driver library (the instructions above).
Hibernate configuration (Use JTDS library)
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
No ADS
Hibernate uses Annotations to describe information for an Entity. It can use the annotations in the API of the hibernate located in the package org.hibernate.annotations or use the annotations in the package javax.persistence of the Java Persistence API. And in fact, the Annotations of the Java Persistence API is preferred.
In this section, I make a list of most common annotations of the Java Persistence API that are involved in the annotation for the Entity.
In this section, I make a list of most common annotations of the Java Persistence API that are involved in the annotation for the Entity.
@Entity
@Entity used to annotate a class is an 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 {
}
Indicating the name of @Entity helps you shorten the HSQL statement. Please look at the 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";
@Table
A table in the DB can have many unique constraints. @Table also allow you to annotate it.
// @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;
}
}
@Id
For example, @Id participates in the ID (Identity) annotationof the Entity, which is equivalent to the understanding that this column is the primary key of the table.
@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;
}
......
}
@GeneratedValue
@Target({METHOD, FIELD})
@Retention(RUNTIME)
public @interface GeneratedValue {
// GenerationType: AUTO, TABLE, SEQUENCE, IDENTITY
GenerationType strategy() default AUTO;
String generator() default "";
}
@GeneratedValue is annotated for Hibernate to automatically generate a value and mounts it into a column in case of inserting a new Entity into the database. It can be mounted on an ID column or some column.
Sometimes, it is also annotated with @Generator
Sometimes, it is also annotated with @Generator
@Column
@Column annotates a column, including the information about column length , allowing null or not.
// Đâ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;
}
@Lob
@Lob are usually annotated with @Column to say that such column is of BLOB typeor CLOB type.
// 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;
}
@Temporal
@Temporal is used to annotate datetime column.
// @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;
}
@ManyToOne
@ManyToOne describes one relationship N-1 (Many -one), which is usually used with @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 has the tools that allow you to generate Entity classes from tables in the Database. And Hibernate also allows you to generate a table from Entity classes, including constraints between tables (Foreign Key). The @ForeignKey annotation allows indicating that the name Foreign Key will be generated.
@ForeignKey is introduced in JPA from 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 tells Hibernate that, "please load data lazily".
For example, you have an Account and call the getOpenBranch() method, it returns a Branch, in Branch object, only branchId field assigned a value, and other fields are not.
In fact, hibernate has not loaded data from the corresponding record of the BRANCH table into this object. It only performs a data query when you do something with the Branch you have just acquired, such as calling the branch.getName() method.
In fact, hibernate has not loaded data from the corresponding record of the BRANCH table into this object. It only performs a data query when you do something with the Branch you have just acquired, such as calling the branch.getName() method.
EAGER:
EAGER tells Hibernate to query all columns of the relevant table.
For example, you have an Account, and call the getOpenBranch() method, it returns the Branch of which values for the fields (name, address, ...) are available. Actually, its data is acquired in a same query with the Account table.
You should use LAZY instead of EAGER for program performance reason.
@OneToMany
@OneToMany is the annotation to retrieve a list of subrecords of current record (This is a many-one relationship). It is the reverse of @ManyToOne annotation, and therefore, it relies on @ManyToOne annotation to define @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;
}
}
@OrderBy
@OrderBy is used to arrange a collection, therefore, it can be used with @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;
}
}
@Transient
Let's see a case:
@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;
}
}
You want to write a getFullName() method, which is only a calculation, not related to any column under the DB. Therefore, you need to use @Transient to notify your intent to Hibernate.
@Transient
public String getFullName() {
return this.firstName+ " " + this.lastName;
}
@Transient
public boolean isManagerEmployee() {
return this.manager != null;
}
@Inheritance
No ADS