Java must-know series: ORM framework and Hibernate

Author: Zen and the Art of Computer Programming

1. Background introduction

Hibernate is a powerful Java persistence framework. It provides an object/relational mapping tool for developers to map object-oriented models to relational databases through simple configuration. Hibernate can easily access, manage, optimize and synchronize relational databases. Due to its ease of use, fast performance, and flexibility, Hibernate has become the most popular ORM framework in the field of Java programming. This series of articles will discuss the basic concepts and technical principles of Hibernate, and how to apply Hibernate to solve practical problems in actual projects.

2. Core concepts and connections

2.1 Hibernate Overview

Hibernate is an open source J2EE framework for ORM (Object-Relational Mapping, Object-Relational Mapping) framework. In Hibernate, we can use object-relational mapping technology to store objects in the application in a relational database. Through Hibernate, we can modify the data in the database while the program is running without recompiling or restarting the server. Therefore, Hibernate provides a programming method similar to object-oriented, allowing us to access the database more easily.

Hibernate has the following main features:

  1. Object/relational mapping: Hibernate enables database tables to correspond to objects in the program, and each object can be easily retrieved, updated, deleted, or added to the database.

  2. SQL generation: Hibernate can automatically generate corresponding SQL statements based on modifications made to application objects, thereby simplifying data reading and writing operations.

  3. Built-in transaction management in the framework: Hibernate provides a transaction management mechanism that can simplify the data processing process of the business logic layer and persistence layer.

  4. Caching: Hibernate supports application-level caching, which can improve query efficiency and reduce the number of database accesses.

  5. Query DSL: Hibernate supports HQL (Hibernate Query Language) query language, which can write complex queries in a SQL-like manner.

2.2 Hibernate architecture

The Hibernate architecture is divided into three layers:

  1. Core Layer: Core Layer includes a Domain Object layer and a Persistence Service layer. The domain object layer defines entity classes, and the objects in this layer have a one-to-one correspondence with the table fields in the relational database; the persistence service layer encapsulates the underlying JDBC API. When CRUD operations are performed on domain objects, they are first converted into SQL statements. Then execute the SQL statement and return the execution results.
  2. Mapping Layer: Mapping Layer is responsible for defining mapping files. The mapping file defines the relationship, constraints and other information between domain objects and database tables, helping Hibernate implement ORM features.
  3. Framework Integration Layer: Framework Integration Layer implements the integration interface between the Hibernate framework and other frameworks. For example, Spring and Struts2 can be integrated with Hibernate through the interface provided by Hibernate.

2.3 Hibernate configuration

Hibernate's configuration file hibernate.cfg.xml is divided into four parts:

  1. SessionFactory settings: SessionFactory represents the core class of Hibernate, including connection pools, thread safety strategies and some Hibernate settings. SessionFactory consists of Hibernate Configuration and Mapping files.
  2. JDBC ConnectionProvider settings: ConnectionProvider implements the acquisition and release strategy of JDBC connections.
  3. TransactionManager settings: TransactionManager implements transaction management strategies.
  4. Classpath settings: Classpath settings contain the jar package path required by Hibernate.

2.4 Entity classes and associations

Entity class: Hibernate entity class is a JavaBean type class, which contains some attributes (fields). These attribute values ​​​​can be accessed through getters and setters, and can be used directly or serialized into JSON or XML format. Examples of entity classes are as follows:

public class Customer {
    private int id;
    private String name;

    // getters and setters omitted for brevity

    public void addOrder(Order order){
        orders.add(order);
    }

    public Collection<Order> getOrders(){
        return orders;
    }
}

@Entity
public class Order {
    @Id
    private int orderId;
    private Date date;

    // many-to-one relationship with customer 
    @OneToOne
    @JoinColumn(name="customer_id")
    private Customer customer;

    // getters and setters omitted for brevity

}

Annotations for entity classes:

  1. @Entity: This annotation is marked on the class, indicating that the class is an entity class.
  2. @Id: This annotation is marked on the primary key attribute, indicating that the value of this attribute uniquely identifies an entity object.
  3. @Column: This annotation is used to define column names and other related properties.
  4. @OneToMany: This annotation defines a one-to-many relationship.
  5. @ManyToOne: This annotation defines a many-to-one relationship.
  6. @ManyToMany: This annotation defines a many-to-many relationship.
  7. @JoinTable: This annotation defines an intermediate table.
  8. @JoinColumn: This annotation defines the foreign key of the main table.

2.5 HQL Query Language

HQL (Hibernate Query Language) is an object-oriented query language provided by Hibernate. HQL can easily perform complex queries and avoid splicing SQL statements.

HQL syntax example:

from Employee as e where e.salary > :minSalary 
and e.department = 'IT' 
group by e.department 
order by e.salary desc

HQL query process:

  1. Use the keyword "from" to specify the name of the entity class to be queried.
  2. The "as" keyword aliases a class.
  3. Use the "where" clause to specify search criteria.
  4. The parameter name after the ":" symbol is used to bind the parameter value.
  5. The "group by" clause is used for grouping.
  6. The "order by" clause is used for sorting.

3. Detailed explanation of core algorithm principles, specific operation steps and mathematical model formulas

3.1 Basic principles of ORM

ORM (Object-Relational Mapping) is a programming technology used to convert relational database tables into object-oriented models so that database data can be manipulated in an object-oriented manner.

There are two main forms of object-relational mapping:

  • One-To-One Mapping: This mapping means that there is a one-to-one relationship between two entity objects. For example, one entity object corresponds to a record in the database, and another entity object also corresponds to a record in the database.
  • One-To-Many Mapping: This mapping means that one entity object corresponds to records in multiple relational database tables. For example, an entity object corresponds to a record in an order table, and the order table may contain records from multiple product information tables.

3.2 Hibernate data persistence process

Hibernate's workflow is shown in the figure below:

  1. Create Session object: Hibernate uses the SessionFactory object to create the Session object, which is the entry point of Hibernate.
  2. Perform add, delete, modify, and query operations: The user performs add, delete, modify, and query operations by calling the Session method, and Hibernate performs corresponding database operations through the underlying JDBC driver.
  3. Operating persistence context: Hibernate maintains a track of the state of the current object through the persistence context.
  4. Writing data to the database: Hibernate writes data to the database based on the contents of the persistence context.
  5. Submit the transaction: If the transaction is successfully submitted, Hibernate will actually write the data to the database.

3.3 Hibernate’s caching mechanism

Hibernate caching mechanism can improve the performance of database access. Hibernate cache is divided into two levels: first-level cache and second-level cache.

First-level cache: Hibernate creates a cache area for each user request, and all the same objects are cached in this memory so that they can be obtained directly from the cache the next time they are accessed, instead of loading again from the database.

Second level cache: Hibernate also maintains a second level cache for each entity bean. When an object in the cache is modified, the object will not be queried from the database again when accessing it for the second time, but will be obtained directly from the cache, thus improving the query speed.

3.4 Declarative transaction management

Hibernate simplifies the data processing process of the business logic layer and persistence layer through the declarative transaction management mechanism. Declarative transaction management is implemented based on AOP (Aspect-Oriented Programming).

Declarative transaction management means that there is no need to explicitly call transaction API functions such as beginTransaction() and commit(). Instead, annotations are used directly inside the transaction code block to declare the boundaries of the transaction. The Hibernate framework will automatically identify the transaction boundaries and automatically Complete transaction management.

4. Specific code examples and detailed explanations

4.1 Configure Hibernate environment

4.1.1 Add Maven dependencies

Add the following dependencies to the project's pom.xml file:

<dependency>
   <groupId>org.hibernate</groupId>
   <artifactId>hibernate-core</artifactId>
   <version>${hibernate.version}</version>
</dependency>
<dependency>
   <groupId>mysql</groupId>
   <artifactId>mysql-connector-java</artifactId>
   <scope>runtime</scope>
</dependency>
<!-- Optional -->
<dependency>
   <groupId>com.h2database</groupId>
   <artifactId>h2</artifactId>
   <version>${h2.version}</version>
   <scope>test</scope>
</dependency>

4.1.2 Create Hibernate configuration file

The Hibernate configuration file hibernate.cfg.xml is as follows:

<?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>

   <!-- SessionFactory settings -->
   <session-factory>
      <!-- Database connection settings -->
      <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
      <property name="connection.url">jdbc:mysql://localhost:3306/mydatabase?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8</property>
      <property name="connection.username">root</property>
      <property name="connection.password"></property>

      <!-- JDBC connection pool (optional) -->
      <!--<property name="pool.size">1</property>-->
      <!--<property name="pool.max_wait">30000</property>-->
      <!--<property name="pool.preferredTestQuery">SELECT 1</property>-->

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

      <!-- Logging -->
      <property name="show_sql">true</property>
      <property name="format_sql">true</property>

      <!-- Mapping information -->
      <mapping resource="com/example/domain/Customer.hbm.xml"/>
      <mapping resource="com/example/domain/Order.hbm.xml"/>

   </session-factory>

</hibernate-configuration>
  • connection.*: Configure database connection parameters.
  • dialect: Set database dialect.
  • show_sql: Set whether to display SQL statements.
  • format_sql: Set whether to format the output SQL statement.
  • <mapping>: Configure entity class mapping file.

4.1.3 Configure entity class mapping file

Example of entity class mapping file:

com/example/domain/Customer.hbm.xml:

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping PUBLIC 
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.example.domain">
   <class name="com.example.domain.Customer" table="customers">
      <id name="id" type="int">
         <generator class="native"/>
      </id>
      <property name="name" type="string"/>
   </class>
</hibernate-mapping>

com/example/domain/Order.hbm.xml:

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping PUBLIC 
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.example.domain">
   <class name="com.example.domain.Order" table="orders">
      <id name="orderId" type="int">
         <generator class="native"/>
      </id>
      <property name="date" type="timestamp"/>
      <many-to-one name="customer" column="customer_id" class="com.example.domain.Customer"/>
   </class>
</hibernate-mapping>
  • <class>: Define entity class.
  • <id>: Define the primary key.
  • <property>: Define common attributes.
  • <many-to-one>: Define one-to-many association.

4.2 Add, delete, modify and check

4.2.1 Inserting data

import org.hibernate.*;
import com.example.domain.Customer;
...
try{
   Session session = factory.openSession();
   Transaction tx = session.beginTransaction();
   try{
      // create a new customer object
      Customer customer = new Customer();
      customer.setName("John Smith");
      // persist the customer object
      session.save(customer);
      tx.commit();
   }catch (HibernateException e){
      if (tx!= null){
         tx.rollback();
      }
      throw e;
   }finally{
      session.close();
   }
}catch (HibernateException e){
   e.printStackTrace();
}
  • Get Session through SessionFactory.
  • Perform the insert operation in a transaction and commit the transaction.
  • If an exception occurs, the transaction is rolled back.

4.2.2 Delete data

import org.hibernate.*;
import com.example.domain.Customer;
...
try{
   Session session = factory.openSession();
   Transaction tx = session.beginTransaction();
   try{
      // delete an existing customer object
      Integer custId =...;
      Customer customer = (Customer) session.load(Customer.class, custId);
      session.delete(customer);
      tx.commit();
   }catch (HibernateException e){
      if (tx!= null){
         tx.rollback();
      }
      throw e;
   }finally{
      session.close();
   }
}catch (HibernateException e){
   e.printStackTrace();
}
  • Get Session through SessionFactory.
  • Perform the delete operation in a transaction and commit the transaction.
  • If an exception occurs, the transaction is rolled back.

4.2.3 Update data

import org.hibernate.*;
import com.example.domain.Customer;
...
try{
   Session session = factory.openSession();
   Transaction tx = session.beginTransaction();
   try{
      // update an existing customer object
      Integer custId =...;
      Customer customer = (Customer) session.load(Customer.class, custId);
      customer.setName("Mary Johnson");
      session.update(customer);
      tx.commit();
   }catch (HibernateException e){
      if (tx!= null){
         tx.rollback();
      }
      throw e;
   }finally{
      session.close();
   }
}catch (HibernateException e){
   e.printStackTrace();
}
  • Get Session through SessionFactory.
  • Perform update operations in a transaction and commit the transaction.
  • If an exception occurs, the transaction is rolled back.

4.2.4 Query data

import org.hibernate.*;
import com.example.domain.Customer;
import java.util.List;
...
try{
   Session session = factory.openSession();
   Transaction tx = session.beginTransaction();
   try{
      // retrieve all customers
      List results = session.createQuery("from Customer").list();
      for (Object result : results){
         System.out.println(((Customer)result).getName());
      }
      tx.commit();
   }catch (HibernateException e){
      if (tx!= null){
         tx.rollback();
      }
      throw e;
   }finally{
      session.close();
   }
}catch (HibernateException e){
   e.printStackTrace();
}
  • Get Session through SessionFactory.
  • Execute query operations in a transaction and commit the transaction.
  • Get a list of query results.
  • If an exception occurs, the transaction is rolled back.

4.3 Paging query

The SQL syntax of paging query is as follows:

SELECT * FROM Customers LIMIT?,?;

?Placeholders are used to represent parameters and are used to pass paging parameters.

In Hibernate, you can use firstResult()the and maxResults()methods to set paging parameters, as shown below:

List results = session.createQuery("from Customer")
                    .setFirstResult((page - 1) * pageSize)
                    .setMaxResults(pageSize)
                    .list();

Here (page - 1) * pageSizerepresents the number of skipped records, pageSizeindicating the number of records per page.

5. Future development trends and challenges

The ORM framework is constantly being updated and upgraded. With the increasing popularity of Web applications, the requirements are becoming more and more complex. The traditional development model based on SQL statements is slowly being eliminated, and new distributed, highly available, and elastically scalable architecture models are gradually emerging. At the same time, people are paying more and more attention to software life cycle management, and microservice architecture is becoming mainstream, which is also driving the update and upgrade of various ORM frameworks.

What are the main directions of the future ORM framework?

  1. Spring Data: This is the ORM framework promoted by the Spring IO Platform Team. Spring Data is an abstraction layer based on Spring FrameWork, providing a unified data access interface on top of the ORM framework. Its advantage is that it provides a more object-oriented way to access data and reduces programmers' learning costs. In addition, Spring Data also provides various Repositories, allowing users to customize data access operations.

  2. Mybatis: MyBatis is an open source project incubated by the Apache Foundation and provides an implementation of the ORM framework. MyBatis works well with other ORM frameworks in Java, such as Hibernate.

  3. EclipseLink: EclipseLink is an open source JPA implementation managed by the Eclipse Foundation. EclipseLink adds many features on top of the JPA specification, including integrated caching, asynchronous query, tenant isolation, etc. Moreover, EclipseLink also has relatively large advantages in performance.

  4. TopLink: TopLink is a very old ORM framework that was once acquired by Sun. Among them, OpenJPA is an open source version of TopLink. However, in recent years, OpenJPA was acquired by Oracle, so now everyone uses Hibernate more.

6. Appendix Frequently Asked Questions and Answers

Guess you like

Origin blog.csdn.net/universsky2015/article/details/133593863