1.Hibernate概述

Hibernate 是由 Gavin King 于 2001 年创建的开放源代码的对象关系框架。它强大且高效的构建具有关系对象持久性和查询服务的 Java 应用程序。

Hibernate 将 Java 类映射到数据库表中,从 Java 数据类型中映射到 SQL 数据类型中,并把开发人员从 95% 的公共数据持续性编程工作中解放出来。

Hibernate 是传统 Java 对象和数据库服务器之间的桥梁,用来处理基于 O/R 映射机制和模式的那些对象。

一文掌握Hibernate_java

Hibernate 优势

  • Hibernate 使用 XML 文件来处理映射 Java 类别到数据库表格中,并且不用编写任何代码。
  • 为在数据库中直接储存和检索 Java 对象提供简单的 APIs。
  • 如果在数据库中或任何其它表格中出现变化,那么仅需要改变 XML 文件属性。
  • 抽象不熟悉的 SQL 类型,并为我们提供工作中所熟悉的 Java 对象。
  • Hibernate 不需要应用程序服务器来操作。
  • 操控你数据库中对象复杂的关联。
  • 最小化与访问数据库的智能提取策略。
  • 提供简单的数据询问。

支持的数据库

Hibernate 支持几乎所有的主要 RDBMS。以下是一些由 Hibernate 所支持的数据库引擎。

  • HSQL Database Engine
  • DB2/NT
  • MySQL
  • PostgreSQL
  • FrontBase
  • Oracle
  • Microsoft SQL Server Database
  • Sybase SQL Server
  • Informix Dynamic Server

支持的技术

Hibernate 支持多种多样的其它技术,包括以下:

  • XDoclet Spring
  • J2EE
  • Eclipse plug-ins
  • Maven

2.Hibernate 架构

架构

Hibernate 架构是分层的,作为数据访问层,你不必知道底层 API 。Hibernate 利用数据库以及配置数据来为应用程序提供持续性服务(以及持续性对象)。

下面是一个非常高水平的 Hibernate 应用程序架构视图。

一文掌握Hibernate_数据库_02

下面是一个详细的 Hibernate 应用程序体系结构视图以及一些重要的类。

一文掌握Hibernate_java_03

Hibernate 使用不同的现存 Java API,比如 JDBC,Java 事务 API(JTA),以及 Java 命名和目录界面(JNDI)。JDBC 提供了一个基本的抽象级别的通用关系数据库的功能, Hibernate 支持几乎所有带有 JDBC 驱动的数据库。JNDI 和 JTA 允许 Hibernate 与 J2EE 应用程序服务器相集成。

下面的部分简要地描述了在 Hibernate 应用程序架构所涉及的每一个类对象。

配置对象

配置对象是你在任何 Hibernate 应用程序中创造的第一个 Hibernate 对象,并且经常只在应用程序初始化期间创造。它代表了 Hibernate 所需一个配置或属性文件。配置对象提供了两种基础组件。

  • 数据库连接:由 Hibernate 支持的一个或多个配置文件处理。这些文件是 hibernate.propertieshibernate.cfg.xml
  • 类映射设置:这个组件创造了 Java 类和数据库表格之间的联系。

SessionFactory 对象

配置对象被用于创造一个 SessionFactory 对象,使用提供的配置文件为应用程序依次配置 Hibernate,并允许实例化一个会话对象。SessionFactory 是一个线程安全对象并由应用程序所有的线程所使用。

SessionFactory 是一个重量级对象所以通常它都是在应用程序启动时创造然后留存为以后使用。每个数据库需要一个 SessionFactory 对象使用一个单独的配置文件。所以如果你使用多种数据库那么你要创造多种 SessionFactory 对象。

Session 对象

一个会话被用于与数据库的物理连接。Session 对象是轻量级的,并被设计为每次实例化都需要与数据库的交互。持久对象通过 Session 对象保存和检索。

Session 对象不应该长时间保持开启状态因为它们通常情况下并非线程安全,并且它们应该按照所需创造和销毁。

Transaction 对象

一个事务代表了与数据库工作的一个单元并且大部分 RDBMS 支持事务功能。在 Hibernate 中事务由底层事务管理器和事务(来自 JDBC 或者 JTA)处理。

这是一个选择性对象,Hibernate 应用程序可能不选择使用这个接口,而是在自己应用程序代码中管理事务。

Query 对象

Query 对象使用 SQL 或者 Hibernate 查询语言(HQL)字符串在数据库中来检索数据并创造对象。一个查询的实例被用于连结查询参数,限制由查询返回的结果数量,并最终执行查询。

Criteria 对象

Criteria 对象被用于创造和执行面向规则查询的对象来检索对象。

3.Hibernate 配置

配置

Hibernate 需要事先知道在哪里找到映射信息,这些映射信息定义了 Java 类怎样关联到数据库表。Hibernate 也需要一套相关数据库和其它相关参数的配置设置。所有这些信息通常是作为一个标准的 Java 属性文件提供的,名叫 hibernate.properties。又或者是作为 XML 文件提供的,名叫 hibernate.cfg.xml

我们将考虑 hibernate.cfg.xml 这个 XML 格式文件,来决定在我的例子里指定需要的 Hibernate 应用属性。这个 XML 文件中大多数的属性是不需要修改的。这个文件保存在应用程序的类路径的根目录里。

Hibernate 属性

下面是一个重要的属性列表,你可能需要表中的属性来在单独的情况下配置数据库。

S.N.

属性和描述

1

hibernate.dialect 这个属性使 Hibernate 应用为被选择的数据库生成适当的 SQL。

2

hibernate.connection.driver_class JDBC 驱动程序类。

3

hibernate.connection.url 数据库实例的 JDBC URL。

4

hibernate.connection.username 数据库用户名。

5

hibernate.connection.password 数据库密码。

6

hibernate.connection.pool_size 限制在 Hibernate 应用数据库连接池中连接的数量。

7

hibernate.connection.autocommit 允许在 JDBC 连接中使用自动提交模式。

如果您正在使用 JNDI 和数据库应用程序服务器然后您必须配置以下属性:

S.N.

属性和描述

1

hibernate.connection.datasource 在应用程序服务器环境中您正在使用的应用程序 JNDI 名。

2

hibernate.jndi.class JNDI 的 InitialContext 类。

3

hibernate.jndi. 在 JNDI的 InitialContext 类中通过任何你想要的 Java 命名和目录接口属性。

4

hibernate.jndi.url 为 JNDI 提供 URL。

5

hibernate.connection.username 数据库用户名。

6

hibernate.connection.password 数据库密码。

Hibernate 和 MySQL 数据库

MySQL 数据库是目前可用的开源数据库系统中最受欢迎的数据库之一。我们要创建 hibernate.cfg.xml 配置文件并将其放置在应用程序的 CLASSPATH 的根目录里。你要确保在你的 MySQL 数据库中 testdb 数据库是可用的,而且你要有一个用户 test 可用来访问数据库。

XML 配置文件一定要遵守 Hibernate 3 Configuration DTD,在 http://hibernate.org/dtd/hibernate-configuration-3.0.dtd. 这个网址中是可以找到的。

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration SYSTEM 
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
   <session-factory>
   <property name="hibernate.dialect">
      org.hibernate.dialect.MySQLDialect
   </property>
   <property name="hibernate.connection.driver_class">
      com.mysql.cj.jdbc.Driver
   </property>

   <!-- Assume test is the database name -->
   <property name="hibernate.connection.url">
      jdbc:mysql://localhost/jpa
   </property>
   <property name="hibernate.connection.username">
      root
   </property>
   <property name="hibernate.connection.password">
      root
   </property>

   <!-- List of XML mapping files -->
   <mapping resource="Employee.hbm.xml"/>

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

上面的配置文件包含与 hibernate-mapping 文件相关的 标签,我们将在下章看看 hibernate mapping 文件到底是什么并且要知道为什么用它,怎样用它。以下是各种重要数据库同源语属性类型的列表:

数据库

方言属性

DB2

org.hibernate.dialect.DB2Dialect

HSQLDB

org.hibernate.dialect.HSQLDialect

HypersonicSQL

org.hibernate.dialect.HSQLDialect

Informix

org.hibernate.dialect.InformixDialect

Ingres

org.hibernate.dialect.IngresDialect

Interbase

org.hibernate.dialect.InterbaseDialect

Microsoft SQL Server 2000

org.hibernate.dialect.SQLServerDialect

Microsoft SQL Server 2005

org.hibernate.dialect.SQLServer2005Dialect

Microsoft SQL Server 2008

org.hibernate.dialect.SQLServer2008Dialect

MySQL

org.hibernate.dialect.MySQLDialect

Oracle (any version)

org.hibernate.dialect.OracleDialect

Oracle 11g

org.hibernate.dialect.Oracle10gDialect

Oracle 10g

org.hibernate.dialect.Oracle10gDialect

Oracle 9i

org.hibernate.dialect.Oracle9iDialect

PostgreSQL

org.hibernate.dialect.PostgreSQLDialect

Progress

org.hibernate.dialect.ProgressDialect

SAP DB

org.hibernate.dialect.SAPDBDialect

Sybase

org.hibernate.dialect.SybaseDialect

Sybase Anywhere

org.hibernate.dialect.SybaseAnywhereDialec

映射类型

当你准备一个 Hibernate 映射文件时,我们已经看到你把 Java 数据类型映射到了 RDBMS 数据格式。在映射文件中已经声明被使用的 types 不是 Java 数据类型;它们也不是 SQL 数据库类型。这种类型被称为 Hibernate 映射类型,可以从 Java 翻译成 SQL,反之亦然。

在这一章中列举出所有的基础,日期和时间,大型数据对象,和其它内嵌的映射数据类型。

原始类型

映射类型

Java 类型

ANSI SQL 类型

integer

int 或 java.lang.Integer

INTEGER

long

long 或 java.lang.Long

BIGINT

short

short 或 java.lang.Short

SMALLINT

float

float 或 java.lang.Float

FLOAT

double

double 或 java.lang.Double

DOUBLE

big_decimal

java.math.BigDecimal

NUMERIC

character

java.lang.String

CHAR(1)

string

java.lang.String

VARCHAR

byte

byte 或 java.lang.Byte

TINYINT

boolean

boolean 或 java.lang.Boolean

BIT

yes/no

boolean 或 java.lang.Boolean

CHAR(1) ('Y' or 'N')

true/false

boolean 或 java.lang.Boolean

CHAR(1) ('T' or 'F')

日期和时间类型

映射类型

Java 类型

ANSI SQL 类型

date

java.util.Date 或 java.sql.Date

DATE

time

java.util.Date 或 java.sql.Time

TIME

timestamp

java.util.Date 或 java.sql.Timestamp

TIMESTAMP

calendar

java.util.Calendar

TIMESTAMP

calendar_date

java.util.Calendar

DATE

二进制和大型数据对象

映射类型

Java 类型

ANSI SQL 类型

binary

byte[]

VARBINARY (or BLOB)

text

java.lang.String

CLOB

serializable

any Java class that implements java.io.Serializable

VARBINARY (or BLOB)

clob

java.sql.Clob

CLOB

blob

java.sql.Blob

BLOB

JDK 相关类型

映射类型

Java 类型

ANSI SQL 类型

class

java.lang.Class

VARCHAR

locale

java.util.Locale

VARCHAR

timezone

java.util.TimeZone

VARCHAR

currency

java.util.Currency

VARCHAR

4.Hibernate 查询操作

maven依赖

<dependencies>
    <!-- EHCache -->
    <dependency>
        <groupId>org.ehcache</groupId>
        <artifactId>ehcache</artifactId>
        <version>3.7.1</version>
    </dependency>
    <!-- EHCache3集成了JCache -->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-jcache</artifactId>
        <version>5.3.7.Final</version>
    </dependency>
    <!-- EHCache 需要的依赖日志包-->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.25</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core -->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>5.3.7.Final</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.21</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.8</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-annotations -->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-annotations</artifactId>
        <version>3.4.0.GA</version>
    </dependency>
</dependencies>

emplpyee.sql

create table EMPLOYEE (
   id INT NOT NULL auto_increment,
   first_name VARCHAR(20) default NULL,
   last_name  VARCHAR(20) default NULL,
   salary     INT  default NULL,
   PRIMARY KEY (id)
);

目录结构

src
└── main
    ├── java
    │   └── com
    │       └── hibernate
    │           ├── filter
    │           │   ├── HibernateInterceptor.java
    │           │   └── MyInterceptor.java
    │           ├── pojo
    │           │   └── Employee.java
    │           └── query
    │               ├── HibernateBatch.java
    │               ├── HibernateCache.java
    │               ├── HibernateCriteria.java
    │               ├── HibernateNative.java
    │               └── HibernateSQL.java
    └── resources
        ├── ehcache.xml
        ├── Employee.hbm.xml
        ├── hibernate.cfg.xml
        └── log4j.properties

8 directories, 12 files

hibernate.cfg.xml

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration SYSTEM
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="hibernate.dialect">
            org.hibernate.dialect.MySQLDialect
        </property>
        <property name="hibernate.connection.driver_class">
            com.mysql.cj.jdbc.Driver
        </property>
        <!-- Assume test is the database name -->
        <property name="hibernate.connection.url">
            jdbc:mysql://localhost/jpa
        </property>
        <property name="hibernate.connection.username">
            root
        </property>
        <property name="hibernate.connection.password">
            root
        </property>
        <!-- List of XML mapping files -->
        <mapping resource="Employee.hbm.xml"/>
    </session-factory>
</hibernate-configuration>

Employee.hbm.xml

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="com.hibernate.pojo.Employee" table="EMPLOYEE">
        <meta attribute="class-description">
            This class contains the employee detail.
        </meta>
        <id name="id" type="int" column="id">
            <!--
            1.<generator> 标签用来自动生成主键值
            2.native 使 Hibernate 可以使用 identity, sequence 或 hilo 算法根据底层数据库的情况来创建主键
            -->
            <generator class="native"/>
        </id>
        <property name="firstName" column="first_name" type="string"/>
        <property name="lastName" column="last_name" type="string"/>
        <property name="salary" column="salary" type="int"/>
    </class>
</hibernate-mapping>

log4j.properties

log4j.rootLogger=INFO,Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
log4j.logger.org.apache=INFO

Employee.java

package com.hibernate.pojo;

import lombok.Data;


import javax.persistence.*;

/**
 * @Author Daniel
 * @Description 实体类
 **/

@Data
@Entity
@Table(name = "EMPLOYEE")
public class Employee {
    @Id
    @GeneratedValue
    @Column(name = "id")
    private int id;
    @Column(name = "first_name")
    private String firstName;
    @Column(name = "last_name")
    private String lastName;
    @Column(name = "salary")
    private int salary;
}

HibernateSQL.java(查询语言)

package com.hibernate.query;

import com.hibernate.pojo.Employee;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.query.Query;

import java.util.List;

/**
 * @Author Daniel
 * @Description Hibernate 查询语言——HQL
 **/
public class HibernateSQL {
    private static SessionFactory factory;

    public static void main(String[] args) {
        try {
            factory = new Configuration().configure().buildSessionFactory();
        } catch (Throwable ex) {
            System.err.println("Failed to create sessionFactory object." + ex);
            throw new ExceptionInInitializerError(ex);
        }
        HibernateSQL bean = new HibernateSQL();

        // 往数据库添加几条记录
        Integer empID1 = bean.addEmployee("Zara", "Ali", 1000);
        Integer empID2 = bean.addEmployee("Daisy", "Das", 5000);
        bean.addEmployee("John", "Paul", 10000);

        // select * from EMPLOYEE;
        bean.listEmployees();

        // update EMPLOYEE set salary=5000 where first_name='Zara';
        bean.updateEmployee(empID1, 5000);

        // delete from EMPLOYEE where first_name='Daisy';
        bean.deleteEmployee(empID2);
        bean.listEmployees();

        // select * from EMPLOYEE where id = 3;
        bean.queryByNamedParameter();
    }

    public Integer addEmployee(String firstName, String lastName, int salary) {
        Session session = factory.openSession();
        Transaction tx = null;
        Integer employeeID = null;
        try {
            tx = session.beginTransaction();
            Employee employee = new Employee();
            employee.setFirstName(firstName);
            employee.setLastName(lastName);
            employee.setSalary(salary);

            employeeID = (Integer) session.save(employee);
            tx.commit();
        } catch (HibernateException e) {
            if (tx != null) tx.rollback();
            e.printStackTrace();
        } finally {
            session.close();
        }
        return employeeID;
    }

    public void listEmployees() {
        Session session = factory.openSession();
        Transaction tx = null;
        try {
            tx = session.beginTransaction();
            // 注意这里不是数据库表名,而是Java中对应的实体类类名!!!
            List employees = session.createQuery("FROM Employee").list();
            for (Object o : employees) {
                Employee employee = (Employee) o;
                System.out.print("First Name: " + employee.getFirstName());
                System.out.print("  Last Name: " + employee.getLastName());
                System.out.println("  Salary: " + employee.getSalary());
            }
            tx.commit();
            System.out.println("------------------------------------------------------");
        } catch (HibernateException e) {
            if (tx != null) tx.rollback();
            e.printStackTrace();
        } finally {
            session.close();
        }
    }

    public void updateEmployee(Integer employeeID, int salary) {
        Session session = factory.openSession();
        Transaction tx = null;
        try {
            tx = session.beginTransaction();
            Employee employee = session.get(Employee.class, employeeID);
            employee.setSalary(salary);
            session.update(employee);
            tx.commit();
        } catch (HibernateException e) {
            if (tx != null) tx.rollback();
            e.printStackTrace();
        } finally {
            session.close();
        }
    }

    public void deleteEmployee(Integer EmployeeID) {
        Session session = factory.openSession();
        Transaction tx = null;
        try {
            tx = session.beginTransaction();
            Employee employee = session.get(Employee.class, EmployeeID);
            session.delete(employee);
            tx.commit();
        } catch (HibernateException e) {
            if (tx != null) tx.rollback();
            e.printStackTrace();
        } finally {
            session.close();
        }
    }

    public void queryByNamedParameter() {
        Session session = factory.openSession();
        String hql = "FROM Employee E WHERE E.id = :employee_id";
        Query query = session.createQuery(hql);
        query.setParameter("employee_id", 3);
        List list = query.list();
        System.out.println(list);
    }
}

输出结果

First Name: Zara  Last Name: Ali  Salary: 1000
First Name: Daisy  Last Name: Das  Salary: 5000
First Name: John  Last Name: Paul  Salary: 10000
------------------------------------------------------
First Name: Zara  Last Name: Ali  Salary: 5000
First Name: John  Last Name: Paul  Salary: 10000
------------------------------------------------------
[Employee(id=3, firstName=John, lastName=Paul, salary=10000)]

HibernateCriteria(标准查询)

package com.hibernate.query;

import com.hibernate.pojo.Employee;
import org.hibernate.*;
import org.hibernate.cfg.Configuration;

import javax.persistence.criteria.*;
import java.util.List;

/**
 * @Author Daniel
 * @Description Hibernate 标准查询——Criteria
 **/
public class HibernateCriteria {
    private static SessionFactory factory;

    public static void main(String[] args) {
        try {
            factory = new Configuration().configure().buildSessionFactory();
        } catch (Throwable ex) {
            System.err.println("Failed to create sessionFactory object." + ex);
            throw new ExceptionInInitializerError(ex);
        }
        HibernateCriteria bean = new HibernateCriteria();

        // 往数据库添加几条记录
        bean.addEmployee("Zara", "Ali", 2000);
        bean.addEmployee("Daisy", "Das", 5000);
        bean.addEmployee("John", "Paul", 5000);
        bean.addEmployee("Mohd", "Yasee", 3000);

        // select * from EMPLOYEE;
        bean.listEmployees();

        // select count(*) from EMPLOYEE;
        bean.countEmployee();

        // select sum(salary) from EMPLOYEE;
        bean.totalSalary();
        factory.close();
    }

    public Integer addEmployee(String firstName, String lastName, int salary) {
        Session session = factory.openSession();
        Transaction tx = null;
        Integer employeeID = null;
        try {
            tx = session.beginTransaction();
            Employee employee = new Employee();
            employee.setFirstName(firstName);
            employee.setLastName(lastName);
            employee.setSalary(salary);
            employeeID = (Integer) session.save(employee);
            tx.commit();
        } catch (HibernateException e) {
            if (tx != null) tx.rollback();
            e.printStackTrace();
        } finally {
            session.close();
        }
        return employeeID;
    }

    // 获取薪水超过2000的雇员信息
    public void listEmployees() {
        Session session = factory.openSession();
        Transaction tx = null;
        try {
            tx = session.beginTransaction();

            // 创建创建CriteriaBuilder对象
            CriteriaBuilder build = session.getCriteriaBuilder();
            // 获取Employee的CriteriaQuery
            CriteriaQuery<Employee> crqEmployee = build.createQuery(Employee.class);
            CriteriaQuery<Long> crqCount = build.createQuery(Long.class);
            // 指定根实体
            Root<Employee> root = crqEmployee.from(crqEmployee.getResultType());
            // 查询操作
            crqEmployee.select(root);
            // 过滤
            CriteriaQuery<Employee> where = crqEmployee.where(build.gt(root.get("salary").as(Integer.class), 2000));
            // 执行查询
            List<Employee> employees = session.createQuery(where).getResultList();

            for (Employee employee : employees) {
                System.out.print("First Name: " + employee.getFirstName());
                System.out.print("  Last Name: " + employee.getLastName());
                System.out.println("  Salary: " + employee.getSalary());
            }
            tx.commit();
            System.out.println("------------------------------------------------------");
        } catch (HibernateException e) {
            if (tx != null) tx.rollback();
            e.printStackTrace();
        } finally {
            session.close();
        }
    }

    public void countEmployee() {
        Session session = factory.openSession();
        Transaction tx = null;
        try {
            tx = session.beginTransaction();

            // 创建创建CriteriaBuilder对象
            CriteriaBuilder build = session.getCriteriaBuilder();
            // 获取Employee的CriteriaQuery
            CriteriaQuery<Employee> crqEmployee = build.createQuery(Employee.class);
            // 获取Long(count)的CriteriaQuery
            CriteriaQuery<Long> crqCount = build.createQuery(Long.class);
            // 指定根实体
            Root<Employee> root = crqCount.from(crqEmployee.getResultType());
            // 查询操作
            crqCount.select(build.count(root));
            // 执行查询
            Long rowCount = session.createQuery(crqCount).getSingleResult();
            System.out.println("Total Count: " + rowCount);
            tx.commit();
        } catch (HibernateException e) {
            if (tx != null) tx.rollback();
            e.printStackTrace();
        } finally {
            session.close();
        }
    }

    public void totalSalary() {
        Session session = factory.openSession();
        Transaction tx = null;
        try {
            tx = session.beginTransaction();

            // 创建创建CriteriaBuilder对象
            CriteriaBuilder build = session.getCriteriaBuilder();
            // 获取Employee的CriteriaQuery
            CriteriaQuery<Employee> crqEmployee = build.createQuery(Employee.class);
            // 获取Long(count)的CriteriaQuery
            CriteriaQuery<Long> crqCount = build.createQuery(Long.class);
            // 指定根实体
            Root<Employee> root = crqCount.from(crqEmployee.getResultType());
            // 查询操作
            crqCount.select(build.sum(root.get("salary").as(Long.class)));
            // 执行查询
            List<Long> totalSalary = session.createQuery(crqCount).getResultList();
            System.out.println("Total Salary: " + totalSalary.get(0));
            tx.commit();
        } catch (HibernateException e) {
            if (tx != null) tx.rollback();
            e.printStackTrace();
        } finally {
            session.close();
        }
    }
}

输出结果

First Name: Zara  Last Name: Ali  Salary: 5000
First Name: John  Last Name: Paul  Salary: 10000
First Name: Daisy  Last Name: Das  Salary: 5000
First Name: John  Last Name: Paul  Salary: 5000
First Name: Mohd  Last Name: Yasee  Salary: 3000
------------------------------------------------------
Total Count: 6
Total Salary: 30000

HibernateNative.java(原生 SQL)

package com.hibernate.query;

import java.util.*;

import com.hibernate.pojo.Employee;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.SessionFactory;
import org.hibernate.Criteria;
import org.hibernate.cfg.Configuration;
import org.hibernate.query.NativeQuery;
import org.hibernate.query.internal.NativeQueryImpl;

/**
 * @Author Daniel
 * @Description Hibernate 原生 SQL——SQL语句
 **/
public class HibernateNative {
    private static SessionFactory factory;

    public static void main(String[] args) {
        try {
            factory = new Configuration().configure().buildSessionFactory();
        } catch (Throwable ex) {
            System.err.println("Failed to create sessionFactory object." + ex);
            throw new ExceptionInInitializerError(ex);
        }
        HibernateNative bean = new HibernateNative();

        // 往数据库添加几条记录
        bean.addEmployee("Zara", "Ali", 2000);
        bean.addEmployee("Daisy", "Das", 5000);
        bean.addEmployee("John", "Paul", 5000);
        bean.addEmployee("Mohd", "Yasee", 3000);

        // select name, salary from EMPLOYEE;
        bean.listEmployeeSalary();

        // select * from EMPLOYEE;
        bean.listEmployeesEntity();
        factory.close();
    }

    public Integer addEmployee(String firstName, String lastName, int salary) {
        Session session = factory.openSession();
        Transaction tx = null;
        Integer employeeID = null;
        try {
            tx = session.beginTransaction();
            Employee employee = new Employee();
            employee.setFirstName(firstName);
            employee.setLastName(lastName);
            employee.setSalary(salary);
            employeeID = (Integer) session.save(employee);
            tx.commit();
        } catch (HibernateException e) {
            if (tx != null) tx.rollback();
            e.printStackTrace();
        } finally {
            session.close();
        }
        return employeeID;
    }

    // 使用原生SQL查询name与salary
    public void listEmployeeSalary() {
        Session session = factory.openSession();
        Transaction tx = null;
        try {
            tx = session.beginTransaction();
            // 这里才是数据库表名
            String sql = "SELECT first_name, salary FROM EMPLOYEE";
            NativeQuery query = session.createSQLQuery(sql);
            query.unwrap(NativeQueryImpl.class).setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP);
            List data = query.list();
            for (Object object : data) {
                Map row = (Map) object;
                System.out.print("First Name: " + row.get("first_name"));
                System.out.println(", Salary: " + row.get("salary"));
            }
            tx.commit();
        } catch (HibernateException e) {
            if (tx != null) tx.rollback();
            e.printStackTrace();
        } finally {
            session.close();
        }
    }

    // 使用原生SQL查询employee实体
    public void listEmployeesEntity() {
        Session session = factory.openSession();
        Transaction tx = null;
        try {
            tx = session.beginTransaction();
            String sql = "SELECT * FROM EMPLOYEE";
            NativeQuery query = session.createSQLQuery(sql);
            query.addEntity(Employee.class);
            List employees = query.list();

            for (Object o : employees) {
                Employee employee = (Employee) o;
                System.out.print("First Name: " + employee.getFirstName());
                System.out.print("  Last Name: " + employee.getLastName());
                System.out.println("  Salary: " + employee.getSalary());
            }
            tx.commit();
            System.out.println("------------------------------------------------------");
        } catch (HibernateException e) {
            if (tx != null) tx.rollback();
            e.printStackTrace();
        } finally {
            session.close();
        }
    }
}

输出结果

First Name: Zara, Salary: 5000
First Name: John, Salary: 10000
First Name: Zara, Salary: 2000
First Name: Daisy, Salary: 5000
First Name: John, Salary: 5000
First Name: Mohd, Salary: 3000
First Name: Zara, Salary: 2000
First Name: Daisy, Salary: 5000
First Name: John, Salary: 5000
First Name: Mohd, Salary: 3000
First Name: Zara  Last Name: Ali  Salary: 5000
First Name: John  Last Name: Paul  Salary: 10000
First Name: Zara  Last Name: Ali  Salary: 2000
First Name: Daisy  Last Name: Das  Salary: 5000
First Name: John  Last Name: Paul  Salary: 5000
First Name: Mohd  Last Name: Yasee  Salary: 3000
First Name: Zara  Last Name: Ali  Salary: 2000
First Name: Daisy  Last Name: Das  Salary: 5000
First Name: John  Last Name: Paul  Salary: 5000
First Name: Mohd  Last Name: Yasee  Salary: 3000
------------------------------------------------------

5.Hibernate 缓存操作

缓存

缓存是关于应用程序性能的优化,降低了应用程序对物理数据源访问的频次,从而提高应用程序的运行性能。

缓存对 Hibernate 来说也是重要的,它使用了如下解释的多级缓存方案:

一文掌握Hibernate_数据库_04

一级缓存

第一级缓存是 Session 缓存并且是一种强制性的缓存,所有的要求都必须通过它。Session 对象在它自己的权利之下,在将它提交给数据库之前保存一个对象。

如果你对一个对象发出多个更新,Hibernate 会尝试尽可能长地延迟更新来减少发出的 SQL 更新语句的数目。如果你关闭 session,所有缓存的对象丢失,或是存留,或是在数据库中被更新。

二级缓存

第二级缓存是一种可选择的缓存并且第一级缓存在任何想要在第二级缓存中找到一个对象前将总是被询问。第二级缓存可以在每一个类和每一个集合的基础上被安装,并且它主要负责跨会话缓存对象。

任何第三方缓存可以和 Hibernate 一起使用。org.hibernate.cache.CacheProvider 接口被提供,它必须实现来给 Hibernate 提供一个缓存实现的解决方法。

查询层次缓存

Hibernate 也实现了一个和第二级缓存密切集成的查询结果集缓存。

这是一个可选择的特点并且需要两个额外的物理缓存区域,它们保存着缓存的查询结果和表单上一次更新时的时间戳。这仅对以同一个参数频繁运行的查询来说是有用的。

第二级缓存

Hibernate 使用默认的一级缓存并且你不用使用一级缓存。让我们直接看向可选的二级缓存。不是所有的类从缓存中获益,所以能关闭二级缓存是重要的。

Hibernate 的二级缓存通过两步设置。第一,你必须决定好使用哪个并发策略。之后,你使用缓存提供程序来配置缓存到期时间和物理缓存属性。

并发策略

一个并发策略是一个中介,它负责保存缓存中的数据项和从缓存中检索它们。如果你将使用一个二级缓存,你必须决定,对于每一个持久类和集合,使用哪一个并发策略。

  • Transactional:为主读数据使用这个策略,在一次更新的罕见状况下并发事务阻止过期数据是关键的。
  • Read-write:为主读数据再一次使用这个策略,在一次更新的罕见状况下并发事务阻止过期数据是关键的。
  • Nonstrict-read-write:这个策略不保证缓存和数据库之间的一致性。如果数据几乎不改变并且过期数据不是很重要,使用这个策略。
  • Read-only:一个适合永不改变数据的并发策略。只为参考数据使用它。

如果我们将为我们的 Employee 类使用二级缓存,让我们使用 read-write 策略来添加需要告诉 Hibernate 来缓存 Employee 实例的映射元素。

修改Employee.hbm.xml

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="com.hibernate.pojo.Employee" table="EMPLOYEE">
        <meta attribute="class-description">
            This class contains the employee detail.
        </meta>
        <!--配置二级缓存类, 添加read-write 策略来缓存 Employee 实例的映射元素-->
        <cache usage="read-write"/>
        <id name="id" type="int" column="id">
            <!--
            1.<generator> 标签用来自动生成主键值
            2.native 使 Hibernate 可以使用 identity, sequence 或 hilo 算法根据底层数据库的情况来创建主键
            -->
            <generator class="native"/>
        </id>
        <property name="firstName" column="first_name" type="string"/>
        <property name="lastName" column="last_name" type="string"/>
        <property name="salary" column="salary" type="int"/>
    </class>
</hibernate-mapping>

usage="read-write" 参数告诉 Hibernate 为定义的缓存使用 read-write 并发策略。

缓存提供者

在考虑你将为你的缓存候选类所使用的并发策略后你的下一步是挑选一个缓存提供者。Hibernate 让你为整个应用程序选择一个单独的缓存提供者。

S.N.

缓存名

描述

1

EHCache

它能在内存或硬盘上缓存并且集群缓存,而且它支持可选的 Hibernate 查询结果缓存。

2

OSCache

支持在一个单独的 JVM 中缓存到内存和硬盘,同时有丰富的过期策略和查询缓存支持。

3

warmCache

一个基于 JGroups 的聚集缓存。它使用集群失效但是不支持 Hibernate 查询缓存。

4

JBoss Cache

一个也基于 JGroups 多播库的完全事务性的复制集群缓存。它支持复制或者失效,同步或异步通信,乐观和悲观锁定。Hibernate 查询缓存被支持。

每一个缓存提供者都不和每个并发策略兼容。以下的兼容性矩阵将帮助你选择一个合适的组合。

策略/提供者

Read-only

Nonstrictread-write

Read-write

Transactional

EHCache

X

X

X


OSCache

X

X

X


SwarmCache

X

X



JBoss Cache

X

X



你将在 hibernate.cfg.xml 配置文件中指定一个缓存提供者。我们选择 EHCache3与JCache 作为我们的二级缓存提供者:

修改hibernate.cfg.xml

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration SYSTEM
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="hibernate.dialect">
            org.hibernate.dialect.MySQLDialect
        </property>
        <property name="hibernate.connection.driver_class">
            com.mysql.cj.jdbc.Driver
        </property>
        <!-- Assume test is the database name -->
        <property name="hibernate.connection.url">
            jdbc:mysql://localhost/jpa
        </property>
        <property name="hibernate.connection.username">
            root
        </property>
        <property name="hibernate.connection.password">
            root
        </property>
        <!-- 开启二级缓存 -->
        <property name="cache.use_second_level_cache">true</property>
        <!-- 开启查询缓存 -->
        <property name="cache.use_query_cache">true</property>
        <!-- 配置二级缓存实现类 -->
        <property name="hibernate.javax.cache.provider">org.ehcache.jsr107.EhcacheCachingProvider</property>
        <property name="cache.region.factory_class">org.hibernate.cache.jcache.internal.JCacheRegionFactory</property>
        <!-- ORM 映射关系 -->
        <mapping resource="Employee.hbm.xml"/>
    </session-factory>
</hibernate-configuration>

现在,你需要指定缓存区域的属性。EHCache 有它自己的配置文件,在resources下新建一个ehcache.xml

ehcache.xml

<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
    <diskStore path="java.io.tmpdir"/>
    <defaultCache
            maxElementsInMemory="1000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="true"
    />
    <cache name="Employee"
           maxElementsInMemory="500"
           eternal="true"
           timeToIdleSeconds="0"
           timeToLiveSeconds="0"
           overflowToDisk="false"
    />
</ehcache>

就是这样,现在我们有 Employee 类的二级缓存并且 Hibernate 现在能命中缓存无论是你导航到 Employee 时或是当你通过标识符上传 Employee 时。

你应该为每个类分析你所有的类并选择合适的缓存策略。有时候,二级缓存可能使应用程序的表现下降。所以首先不允许缓存用基准程序测试你的应用程序,然后开启合适的缓存,之后检测表现是推荐的。如果缓存不提升系统表现那么支持任何类型的缓存都是没有意义的。

HibernateCache.java

package com.hibernate.query;

import com.hibernate.pojo.Employee;
import org.hibernate.*;
import org.hibernate.cfg.Configuration;
import org.hibernate.query.Query;

import java.util.List;

/**
 * @Author Daniel
 * @Description Hibernate 缓存操作
 **/
public class HibernateCache {
    private static SessionFactory factory;

    public static void main(String[] args) {
        try {
            factory = new Configuration().configure().buildSessionFactory();
        } catch (Throwable ex) {
            System.err.println("Failed to create sessionFactory object." + ex);
            throw new ExceptionInInitializerError(ex);
        }
        HibernateCache bean = new HibernateCache();
        bean.cacheQuery();
        factory.close();
    }

    public void cacheQuery() {
        Session session = factory.openSession();
        Query query = session.createQuery("FROM Employee ");
        // 使用查询缓存
        query.setCacheable(true);
        // 细粒度的缓存支持,告诉 Hibernate 存储和寻找缓存 employee 区域的查询
        query.setCacheRegion("employee");
        List employees = query.list();
        for (Object o : employees) {
            Employee employee = (Employee) o;
            System.out.print("First Name: " + employee.getFirstName());
            System.out.print("  Last Name: " + employee.getLastName());
            System.out.println("  Salary: " + employee.getSalary());
        }
    }
}

可以看到日志中成功输出了缓存的日志信息

一文掌握Hibernate_java_05

注意:

日志中的警告

2021-07-07 09:46:07,790 [main] WARN [org.hibernate.orm.cache] - HHH90001006: Missing cache[employee] was created on-the-fly. The created cache will use a provider-specific default configuration: make sure you defined one. You can disable this warning by setting 'hibernate.javax.cache.missing_cache_strategy' to 'create'.

意思是我们需要配置hibernate.javax.cache.missing_cache_strategy=create,表示如果没有在配置文件中配置缓存,将会自动创建,这里的配置文件是hazelcast.xml,但是这里我们并没有这个文件,hazelcast会自动读取默认的一份配置文件,在hazelcast的jar包中有hazelcast-default.xml文件,记录了默认配置,要自定义配置时,复制一份,重命名为hazelcast.xml,放到resources目录下,会自动读到,所以可以不用配置

6.Hibernate 批处理

修改hibernate.cfg.xml

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration SYSTEM
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="hibernate.dialect">
            org.hibernate.dialect.MySQLDialect
        </property>
        <property name="hibernate.connection.driver_class">
            com.mysql.cj.jdbc.Driver
        </property>
        <!-- Assume test is the database name -->
        <property name="hibernate.connection.url">
            jdbc:mysql://localhost/jpa
        </property>
        <property name="hibernate.connection.username">
            root
        </property>
        <property name="hibernate.connection.password">
            root
        </property>
        <!-- 开启二级缓存 -->
        <property name="cache.use_second_level_cache">true</property>
        <!-- 开启查询缓存 -->
        <property name="cache.use_query_cache">true</property>
        <!-- 配置二级缓存实现类 -->
        <property name="hibernate.javax.cache.provider">org.ehcache.jsr107.EhcacheCachingProvider</property>
        <property name="cache.region.factory_class">org.hibernate.cache.jcache.internal.JCacheRegionFactory</property>
        <property name="hibernate.jdbc.batch_size">
            50
        </property>
        <!-- ORM 映射关系 -->
        <mapping resource="Employee.hbm.xml"/>
    </session-factory>
</hibernate-configuration>

HibernateBatch.java

package com.hibernate.query;

import com.hibernate.pojo.Employee;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.query.Query;

import java.util.List;

/**
 * @Author Daniel
 * @Description Hibernate 批处理
 **/
public class HibernateBatch {
    private static SessionFactory factory;

    public static void main(String[] args) {
        try {
            factory = new Configuration().configure().buildSessionFactory();
        } catch (Throwable ex) {
            System.err.println("Failed to create sessionFactory object." + ex);
            throw new ExceptionInInitializerError(ex);
        }
        HibernateBatch bean = new HibernateBatch();
        bean.batch();
        factory.close();
    }


    public void batch() {
        Session session = factory.openSession();
        Transaction tx = null;
        try {
            tx = session.beginTransaction();
            for (int i = 0; i < 1000; i++) {
                String firstName = "First Name " + i;
                String lastName = "Last Name " + i;
                Employee employee = new Employee();
                employee.setFirstName(firstName);
                employee.setLastName(lastName);
                employee.setSalary(i);
                session.save(employee);
                if (i % 50 == 0) {
                    session.flush();
                    session.clear();
                }
            }
            tx.commit();
        } catch (HibernateException e) {
            if (tx != null) tx.rollback();
            e.printStackTrace();
        } finally {
            session.close();
        }
    }


}

这里用sql来查询表中的数据

select count(*) from EMPLOYEE;


mysql> select count(*) from EMPLOYEE;
+----------+
| count(*) |
+----------+
|     1010 |
+----------+
1 row in set (0.01 sec)

7.Hibernate 拦截器

拦截器

你已经学到,在 Hibernate 中,一个对象将被创建和保持。一旦对象已经被修改,它必须被保存到数据库里。这个过程持续直到下一次对象被需要,它将被从持久的存储中加载。

因此一个对象通过它生命周期中的不同阶段,并且 Interceptor 接口提供了在不同阶段能被调用来进行一些所需要的任务的方法。这些方法是从会话到应用程序的回调函数,允许应用程序检查或操作一个持续对象的属性,在它被保存,更新,删除或上传之前。以下是在 Interceptor 接口中可用的所有方法的列表。

S.N.

方法和描述

1

findDirty() 这个方法在当 flush() 方法在一个 Session 对象上被调用时被调用。

2

instantiate() 这个方法在一个持续的类被实例化时被调用。

3

isUnsaved() 这个方法在当一个对象被传到 saveOrUpdate() 方法时被调用。

4

onDelete() 这个方法在一个对象被删除前被调用。

5

onFlushDirty() 这个方法在当 Hibernate 探测到一个对象在一次 flush(例如,更新操作)中是脏的(例如,被修改)时被调用。

6

onLoad() 这个方法在一个对象被初始化之前被调用。

7

onSave() 这个方法在一个对象被保存前被调用。

8

postFlush() 这个方法在一次 flush 已经发生并且一个对象已经在内存中被更新后被调用。

9

preFlush() 这个方法在一次 flush 前被调用。

Hibernate 拦截器给予了我们一个对象如何应用到应用程序和数据库的总控制。

如何使用拦截器?

为了创建一个拦截器你可以直接实现 Interceptor 类或者继承 EmptyInterceptor 类。以下是简单的使用 Hibernate 拦截器功能的步骤。

MyInterceptor.java

package com.hibernate.filter;

import com.hibernate.pojo.Employee;

import java.io.Serializable;
import java.util.Iterator;

import org.hibernate.EmptyInterceptor;
import org.hibernate.type.Type;

/**
 * @Author Daniel
 * @Description 自定义拦截器
 **/
public class MyInterceptor extends EmptyInterceptor {

    // 更新数据库时执行的方法
    public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) {
        if (entity instanceof Employee) {
            System.out.println("Update Operation");
            return true;
        }
        return false;
    }


    // 添加数据时执行的方法
    public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
        if (entity instanceof Employee) {
            System.out.println("Create Operation");
            return true;
        }
        return false;
    }

    // commit前执行的方法
    public void preFlush(Iterator iterator) {
        System.out.println("preFlush");
    }

    // commit后执行的方法
    public void postFlush(Iterator iterator) {
        System.out.println("postFlush");
    }
}

HibernateInterceptor.java

package com.hibernate.filter;

import com.hibernate.pojo.Employee;

import java.util.List;
import java.util.Iterator;

import org.hibernate.*;
import org.hibernate.cfg.Configuration;

/**
 * @Author Daniel
 * @Description Hibernate 拦截器
 **/
public class HibernateInterceptor {
    private static SessionFactory factory;

    public static void main(String[] args) {
        try {
            factory = new Configuration().configure().buildSessionFactory();
        } catch (Throwable ex) {
            System.err.println("Failed to create sessionFactory object." + ex);
            throw new ExceptionInInitializerError(ex);
        }

        HibernateInterceptor bean = new HibernateInterceptor();

        // 往数据库添加几条记录
        Integer empID1 = bean.addEmployee("Zara", "Ali", 1000);
        Integer empID2 = bean.addEmployee("Daisy", "Das", 5000);
        bean.addEmployee("John", "Paul", 10000);

        // select * from EMPLOYEE;
        bean.listEmployees();

        // update EMPLOYEE set salary=5000 where first_name='Zara';
        bean.updateEmployee(empID1, 5000);

        // delete from EMPLOYEE where first_name='Daisy';
        bean.deleteEmployee(empID2);

        bean.listEmployees();
        factory.close();
    }


    public Integer addEmployee(String firstName, String lastName, int salary) {

        Session session = factory.withOptions().interceptor(new MyInterceptor()).openSession();
        Transaction tx = null;
        Integer employeeID = null;
        try {
            tx = session.beginTransaction();
            Employee employee = new Employee();
            employee.setFirstName(firstName);
            employee.setLastName(lastName);
            employee.setSalary(salary);
            employeeID = (Integer) session.save(employee);
            tx.commit();
        } catch (HibernateException e) {
            if (tx != null) tx.rollback();
            e.printStackTrace();
        } finally {
            session.close();
        }
        return employeeID;
    }

    public void listEmployees() {
        Session session = factory.withOptions().interceptor(new MyInterceptor()).openSession();
        Transaction tx = null;
        try {
            tx = session.beginTransaction();
            List employees = session.createQuery("FROM Employee").list();
            for (Iterator iterator =
                 employees.iterator(); iterator.hasNext(); ) {
                Employee employee = (Employee) iterator.next();
                System.out.print("First Name: " + employee.getFirstName());
                System.out.print("  Last Name: " + employee.getLastName());
                System.out.println("  Salary: " + employee.getSalary());
            }
            tx.commit();
        } catch (HibernateException e) {
            if (tx != null) tx.rollback();
            e.printStackTrace();
        } finally {
            session.close();
        }
    }

    public void updateEmployee(Integer EmployeeID, int salary) {
        Session session = factory.withOptions().interceptor(new MyInterceptor()).openSession();
        Transaction tx = null;
        try {
            tx = session.beginTransaction();
            Employee employee = session.get(Employee.class, EmployeeID);
            employee.setSalary(salary);
            session.update(employee);
            tx.commit();
        } catch (HibernateException e) {
            if (tx != null) tx.rollback();
            e.printStackTrace();
        } finally {
            session.close();
        }
    }

    public void deleteEmployee(Integer EmployeeID) {
        Session session = factory.withOptions().interceptor(new MyInterceptor()).openSession();
        Transaction tx = null;
        try {
            tx = session.beginTransaction();
            Employee employee = session.get(Employee.class, EmployeeID);
            session.delete(employee);
            tx.commit();
        } catch (HibernateException e) {
            if (tx != null) tx.rollback();
            e.printStackTrace();
        } finally {
            session.close();
        }
    }
}

由于上一步批处理添加了很多数据,这里我们先清空数据库表然后再运行

truncate table employee;

输出结果

Create Operation
preFlush
postFlush
Create Operation
preFlush
postFlush
Create Operation
preFlush
postFlush
2021-07-07 09:52:28,655 [main] INFO  [org.hibernate.hql.internal.QueryTranslatorFactoryInitiator] - HHH000397: Using ASTQueryTranslatorFactory
First Name: Zara  Last Name: Ali  Salary: 1000
First Name: Daisy  Last Name: Das  Salary: 5000
First Name: John  Last Name: Paul  Salary: 10000
preFlush
postFlush
preFlush
Update Operation
postFlush
preFlush
postFlush
First Name: Zara  Last Name: Ali  Salary: 5000
First Name: John  Last Name: Paul  Salary: 10000
preFlush
postFlush