Hibernate - 快速指南


Hibernate - ORM 概述

什么是 JDBC?

JDBC 代表Java 数据库连接。它提供了一组Java API,用于从Java程序访问关系数据库。这些 Java API 使 Java 程序能够执行 SQL 语句并与任何兼容 SQL 的数据库进行交互。

JDBC 提供了一种灵活的体系结构来编写独立于数据库的应用程序,该应用程序可以在不同平台上运行并与不同的 DBMS 交互,而无需任何修改。

JDBC 的优点和缺点

JDBC 的优点 JDBC 的缺点

干净简单的 SQL 处理

大数据下性能良好

非常适合小型应用

简单的语法很容易学习

如果在大型项目中使用则复杂

编程开销大

无封装

MVC概念很难实现

查询是特定于 DBMS 的

为什么选择对象关系映射 (ORM)?

当我们使用面向对象的系统时,对象模型和关系数据库之间存在不匹配。RDBMS 以表格格式表示数据,而面向对象的语言(例如 Java 或 C#)将其表示为对象的互连图。

考虑以下具有适当构造函数和相关公共函数的 Java 类 -

public class Employee {
   private int id;
   private String first_name; 
   private String last_name;   
   private int salary;  

   public Employee() {}
   public Employee(String fname, String lname, int salary) {
      this.first_name = fname;
      this.last_name = lname;
      this.salary = salary;
   }
   
   public int getId() {
      return id;
   }
   
   public String getFirstName() {
      return first_name;
   }
   
   public String getLastName() {
      return last_name;
   }
   
   public int getSalary() {
      return salary;
   }
}

考虑上述对象将被存储和检索到以下 RDBMS 表中 -

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)
);

第一个问题,如果我们在开发了几个页面或应用程序后需要修改数据库的设计怎么办?其次,在关系数据库中加载和存储对象使我们面临以下五个不匹配问题 -

先生。 不匹配和描述
1

粒度

有时,您将拥有一个对象模型,其中的类数量比数据库中相应表的数量还多。

2

遗产

RDBMS 没有定义任何类似于继承的东西,继承是面向对象编程语言中的自然范例。

3

身份

RDBMS 准确地定义了一个“相同性”概念:主键。然而,Java 定义了对象标识 (a==b) 和对象相等性 (a.equals(b))。

4

协会

面向对象的语言使用对象引用来表示关联,而 RDBMS 将关联表示为外键列。

5

导航

Java 和 RDBMS 中访问对象的方式根本不同。

对象关系映射(ORM)是处理所有上述阻抗不匹配的解决方案

什么是 ORM?

ORM 代表对象关系映射(ORM) 是一种用于在关系数据库和面向对象编程语言(例如 Java、C# 等)之间转换数据的编程技术

ORM 系统比普通 JDBC 具有以下优点:

先生。 优点
1 让我们的业务代码访问对象而不是数据库表。
2 对 OO 逻辑隐藏 SQL 查询的详细信息。
3 基于 JDBC“底层”。
4 无需处理数据库实现。
5 基于业务概念而不是数据库结构的实体。
6 事务管理和自动密钥生成。
7 应用程序的快速开发。

ORM 解决方案由以下四个实体组成 -

先生。 解决方案
1 用于对持久类的对象执行基本 CRUD 操作的 API。
2 用于指定引用类和类属性的查询的语言或 API。
3 用于指定映射元数据的可配置工具。
4 一种与事务对象交互以执行脏检查、惰性关联获取和其他优化功能的技术。

Java ORM 框架

Java 中有多种持久框架和 ORM 选项。持久框架是一种 ORM 服务,它将对象存储和检索到关系数据库中。

  • Enterprise JavaBeans 实体 Bean
  • Java数据对象
  • 蓖麻
  • 顶联
  • 春季DAO
  • Hibernate
  • 还有很多

Hibernate - 概述

Hibernate 是JAVA 的对象关系映射(ORM) 解决方案。它是 Gavin King 在 2001 年创建的一个开源持久性框架。它是适用于任何 Java 应用程序的强大、高性能的对象关系持久性和查询服务。

Hibernate 将 Java 类映射到数据库表,以及从 Java 数据类型映射到 SQL 数据类型,并将开发人员从 95% 的常见数据持久性相关编程任务中解放出来。

Hibernate 位于传统 Java 对象和数据库服务器之间,根据适当的 O/R 机制和模式处理持久保存这些对象的所有工作。

Hibernate位置

Hibernate的优点

  • Hibernate 负责使用 XML 文件将 Java 类映射到数据库表,而无需编写任何代码行。

  • 提供简单的 API,用于直接在数据库中存储和检索 Java 对象。

  • 如果数据库或任何表中有更改,则只需更改 XML 文件属性。

  • 抽象出不熟悉的 SQL 类型并提供一种解决熟悉的 Java 对象的方法。

  • Hibernate 不需要应用程序服务器来运行。

  • 操作数据库对象的复杂关联。

  • 通过智能获取策略最大限度地减少数据库访问。

  • 提供简单的数据查询。

支持的数据库

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

  • HSQL数据库引擎
  • DB2/NT
  • MySQL
  • PostgreSQL
  • 前端基地
  • 甲骨文
  • 微软SQL服务器数据库
  • 赛贝斯SQL服务器
  • Informix 动态服务器

支持的技术

Hibernate 支持各种其他技术,包括 -

  • XDoclet 弹簧
  • J2EE
  • Eclipse 插件
  • 梅文

Hibernate - 架构

Hibernate 具有分层架构,帮助用户无需了解底层 API 即可进行操作。Hibernate 利用数据库和配置数据向应用程序提供持久性服务(和持久性对象)。

以下是 Hibernate 应用程序架构的高级视图。

Hibernate 高级视图

以下是 Hibernate 应用程序架构及其重要核心类的详细视图。

Hibernate架构

Hibernate 使用各种现有的 Java API,例如 JDBC、Java 事务 API (JTA) 和 Java 命名和目录接口 (JNDI)。JDBC 提供了关系数据库常见功能的基本抽象级别,允许 Hibernate 支持几乎所有具有 JDBC 驱动程序的数据库。JNDI 和 JTA 允许 Hibernate 与 J2EE 应用程序服务器集成。

以下部分简要描述了 Hibernate 应用程序架构中涉及的每个类对象。

配置对象

Configuration 对象是您在任何 Hibernate 应用程序中创建的第一个 Hibernate 对象。它通常在应用程序初始化期间仅创建一次。它代表 Hibernate 所需的配置或属性文件。

配置对象提供两个关键组件 -

  • 数据库连接- 这是通过 Hibernate 支持的一个或多个配置文件来处理的。这些文件是hibernate.propertieshibernate.cfg.xml

  • 类映射设置- 该组件创建 Java 类和数据库表之间的连接。

会话工厂对象

配置对象用于创建 SessionFactory 对象,该对象又使用提供的配置文件为应用程序配置 Hibernate,并允许实例化 Session 对象。SessionFactory 是一个线程安全对象,由应用程序的所有线程使用。

SessionFactory是一个重量级对象;它通常在应用程序启动期间创建并保留以供以后使用。您需要使用单独的配置文件为每个数据库提供一个 SessionFactory 对象。因此,如果您使用多个数据库,则必须创建多个 SessionFactory 对象。

会话对象

会话用于获取与数据库的物理连接。Session 对象是轻量级的,旨在每次需要与数据库交互时实例化。持久对象通过会话对象保存和检索。

会话对象不应该长时间保持打开状态,因为它们通常不是线程安全的,应该根据需要创建和销毁它们。

交易对象

事务代表数据库的一个工作单元,大多数 RDBMS 支持事务功能。Hibernate 中的事务由底层事务管理器和事务(来自 JDBC 或 JTA)处理。

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

查询对象

查询对象使用 SQL 或 Hibernate 查询语言 (HQL) 字符串从数据库检索数据并创建对象。Query 实例用于绑定查询参数、限制查询返回结果的数量,最后执行查询。

标准对象

Criteria 对象用于创建和执行面向对象的条件查询来检索对象。

Hibernate - 环境

本章介绍如何安装 Hibernate 和其他相关软件包来为 Hibernate 应用程序准备环境。我们将使用 MySQL 数据库来试验 Hibernate 示例,因此请确保您已经设置了 MySQL 数据库。有关 MySQL 的更多详细信息,您可以查看我们的MySQL 教程

下载Hibernate

假设您的系统上已经安装了最新版本的 Java。以下是在您的系统上下载并安装 Hibernate 的简单步骤 -

  • 选择是要在 Windows 还是 Unix 上安装 Hibernate,然后继续下一步,下载适用于 Windows 的 .zip 文件和适用于 Unix 的 .tz 文件。

  • 从http://www.hibernate.org/downloads下载最新版本的 Hibernate 。

  • 在编写本教程时,我下载了hibernate-distribution3.6.4.Final,当您解压下载的文件时,它将为您提供如下图所示的目录结构

Hibernate目录

安装Hibernate

下载并解压最新版本的 Hibernate 安装文件后,您需要执行以下两个简单步骤。确保正确设置 CLASSPATH 变量,否则在编译应用程序时将遇到问题。

  • 现在,将/lib中的所有库文件复制到 CLASSPATH 中,并更改类路径变量以包含所有 JAR -

  • 最后,将hibernate3.jar文件复制到 CLASSPATH 中。该文件位于安装的根目录中,是 Hibernate 完成其工作所需的主要 JAR。

Hibernate先决条件

以下是 Hibernate 所需的包/库的列表,您应该在开始使用 Hibernate 之前安装它们。要安装这些软件包,您必须将库文件从/lib复制到 CLASSPATH 中,并相应地更改 CLASSPATH 变量。

先生。 包/库
1

dom4j

XML 解析www.dom4j.org/

2

夏兰

XSLT 处理器https://xml.apache.org/xalan-j/

3

薛西斯

Xerces Java 解析器https://xml.apache.org/xerces-j/

4

程序库

在运行时对 Java 类进行适当的更改http://cglib.sourceforge.net/

5

日志4j

记录 Faremwork https://logging.apache.org/log4j

6

下议院

日志记录、电子邮件等https://jakarta.apache.org/commons

7

SLF4J

Java 日志外观https://www.slf4j.org

Hibernate - 配置

Hibernate 需要提前知道在哪里可以找到定义 Java 类与数据库表如何关联的映射信息。Hibernate还需要一组与数据库和其他相关参数相关的配置设置。所有这些信息通常作为名为hibernate.properties的标准 Java 属性文件或名为hibernate.cfg.xml的 XML 文件提供。

我将考虑使用 XML 格式的文件hibernate.cfg.xml在我的示例中指定所需的 Hibernate 属性。大多数属性都采用默认值,除非确实需要,否则不需要在属性文件中指定它们。该文件保存在应用程序类路径的根目录中。

Hibernate属性

以下是重要属性的列表,您将需要在独立情况下配置数据库 -

先生。 属性及说明
1

hibernate方言

此属性使 Hibernate 为所选数据库生成适当的 SQL。

2

hibernate.connection.driver_class

JDBC 驱动程序类。

3

hibernate.connection.url

数据库实例的 JDBC URL。

4

hibernate.connection.用户名

数据库用户名。

5

Hibernate.连接.密码

数据库密码。

6

hibernate.connection.pool_size

限制 Hibernate 数据库连接池中等待的连接数。

7

hibernate.connection.autocommit

允许 JDBC 连接使用自动提交模式。

如果您将数据库与应用程序服务器和 JNDI 一起使用,那么您必须配置以下属性 -

先生。 属性及说明
1

hibernate.connection.datasource

在应用程序服务器上下文中定义的 JNDI 名称,您正在将其用于应用程序。

2

hibernate.jndi.类

JNDI 的 InitialContext 类。

3

hibernate.jndi.<JNDI 属性名称>

将您喜欢的任何 JNDI 属性传递给 JNDI InitialContext

4

hibernate.jndi.url

提供 JNDI 的 URL。

5

hibernate.connection.用户名

数据库用户名。

6

Hibernate.连接.密码

数据库密码。

使用 MySQL 数据库进行Hibernate

MySQL 是当今最流行的开源数据库系统之一。让我们创建hibernate.cfg.xml配置文件并将其放置在应用程序类路径的根目录中。您必须确保 MySQL 数据库中有可用的testdb数据库,并且有可用于访问该数据库的用户test 。

XML 配置文件必须符合 Hibernate 3 配置 DTD,该 DTD 可以从http://www.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.jdbc.Driver
      </property>
      
      <!-- Assume test is the database name -->
      
      <property name = "hibernate.connection.url">
         jdbc:mysql://localhost/test
      </property>
      
      <property name = "hibernate.connection.username">
         root
      </property>
      
      <property name = "hibernate.connection.password">
         root123
      </property>
      
      <!-- List of XML mapping files -->
      <mapping resource = "Employee.hbm.xml"/>
      
   </session-factory>
</hibernate-configuration>

上面的配置文件包含<mapping>标签,这些标签与 hibernate 映射文件相关,我们将在下一章中看到 hibernate 映射文件到底是什么以及我们如何以及为什么使用它?

以下是各种重要数据库方言属性类型的列表 -

先生。 数据库和方言属性
1

数据库2

org.hibernate.dialect.DB2Dialect

2

HSQL数据库

org.hibernate.dialect.HSQLDialect

3

超音速SQL

org.hibernate.dialect.HSQLDialect

4

信息系统

org.hibernate.dialect.InformixDialect

5

安格尔

org.hibernate.dialect.IngresDialect

6

英特贝斯

org.hibernate.dialect.InterbaseDialect

7

微软SQL服务器2000

org.hibernate.dialect.SQLServerDialect

8

微软SQL服务器2005

org.hibernate.dialect.SQLServer2005Dialect

9

微软 SQL Server 2008

org.hibernate.dialect.SQLServer2008Dialect

10

MySQL

org.hibernate.dialect.MySQLDialect

11

Oracle(任何版本)

org.hibernate.dialect.OracleDialect

12

甲骨文11g

org.hibernate.dialect.Oracle10gDialect

13

甲骨文10g

org.hibernate.dialect.Oracle10gDialect

14

甲骨文9i

org.hibernate.dialect.Oracle9iDialect

15

PostgreSQL

org.hibernate.dialect.PostgreSQLDialect

16

进步

org.hibernate.dialect.ProgressDialect

17 号

SAP数据库

org.hibernate.dialect.SAPDBDialect

18

赛贝斯

org.hibernate.dialect.SybaseDialect

19

Sybase 无处不在

org.hibernate.dialect.SybaseAnywhereDialect

Hibernate - 会话

会话用于获取与数据库的物理连接。Session 对象是轻量级的,旨在每次需要与数据库交互时实例化。持久对象通过会话对象保存和检索。

会话对象不应该长时间保持打开状态,因为它们通常不是线程安全的,应该根据需要创建和销毁它们。Session的主要功能是为映射实体类的实例提供、创建、读取和删除操作。

在给定时间点,实例可能存在以下三种状态之一 -

  • 瞬态- 持久类的新实例,它不与会话关联,并且在数据库中没有表示形式,并且没有标识符值被 Hibernate 视为瞬态。

  • 持久性- 您可以通过将瞬态实例与会话关联来使其持久化。持久实例在数据库中具有表示形式、标识符值并与会话关联。

  • 分离- 一旦我们关闭 Hibernate 会话,持久实例将成为分离实例。

如果 Session 实例的持久类是可序列化的,则该实例也是可序列化的。典型的交易应使用以下习惯用法 -

Session session = factory.openSession();
Transaction tx = null;

try {
   tx = session.beginTransaction();
   // do some work
   ...
   tx.commit();
}

catch (Exception e) {
   if (tx!=null) tx.rollback();
   e.printStackTrace(); 
} finally {
   session.close();
}

如果Session抛出异常,则事务必须回滚并且会话必须被丢弃。

会话接口方法

Session接口提供了许多方法,但我将仅列出一些重要的方法,我们将在本教程中使用它们。您可以查看 Hibernate 文档以获取与SessionSessionFactory关联的方法的完整列表。

先生。 会议方法及说明
1

交易开始交易()

开始一个工作单元并返回关联的 Transaction 对象。

2

无效取消查询()

取消当前查询的执行。

3

无效清除()

完全清除会话。

4

连接关闭()

通过释放 JDBC 连接并进行清理来结束会话。

5

Criteria createCriteria(持久类类)

为给定的实体类或实体类的超类创建一个新的 Criteria 实例。

6

条件 createCriteria(String 实体名称)

为给定的实体名称创建一个新的 Criteria 实例。

7

可序列化的 getIdentifier(Object 对象)

返回与此会话关联的给定实体的标识符值。

8

查询createFilter(对象集合,字符串queryString)

为给定的集合和过滤器字符串创建一个新的 Query 实例。

9

查询createQuery(字符串queryString)

为给定的 HQL 查询字符串创建一个新的 Query 实例。

10

SQLQuery createSQLQuery(字符串查询字符串)

为给定的 SQL 查询字符串创建一个新的 SQLQuery 实例。

11

无效删除(对象对象)

从数据存储中删除持久实例。

12

void delete(String 实体名称, Object 对象)

从数据存储中删除持久实例。

13

会话 get(String 实体名称, 可序列化 id)

返回具有给定标识符的给定命名实体的持久实例,如果不存在这样的持久实例,则返回 null。

14

SessionFactory getSessionFactory()

获取创建此会话的会话工厂。

15

无效刷新(对象对象)

从底层数据库重新读取给定实例的状态。

16

交易 getTransaction()

获取与此会话关联的事务实例。

17 号

布尔值 isConnected()

检查会话当前是否已连接。

18

布尔 isDirty()

此会话是否包含任何必须与数据库同步的更改?

19

布尔值 isOpen()

检查会话是否仍处于打开状态。

20

可序列化保存(Object对象)

保留给定的瞬态实例,首先分配生成的标识符。

21

无效saveOrUpdate(对象对象)

保存(Object)或更新(Object)给定实例。

22

无效更新(对象对象)

使用给定分离实例的标识符更新持久实例。

23

void update(String 实体名称, Object 对象)

使用给定分离实例的标识符更新持久实例。

Hibernate - 持久类

Hibernate 的整个概念是从 Java 类属性中获取值并将它们保存到数据库表中。映射文档帮助 Hibernate 确定如何从类中提取值并将它们与表和关联字段进行映射。

其对象或实例将存储在数据库表中的 Java 类在 Hibernate 中称为持久类。如果这些类遵循一些简单的规则(也称为普通旧 Java 对象(POJO) 编程模型),Hibernate 效果最佳。

持久类有以下主要规则,但是,这些规则都不是硬性要求 -

  • 所有要保留的 Java 类都需要一个默认构造函数。

  • 所有类都应包含一个 ID,以便轻松识别 Hibernate 和数据库中的对象。此属性映射到数据库表的主键列。

  • 所有要保留的属性都应声明为私有,并具有以 JavaBean 风格定义的getXXXsetXXX方法。

  • Hibernate 的一个核心特性是代理,它依赖于持久类是非最终的,还是声明所有公共方法的接口的实现。

  • 所有不扩展或实现 EJB 框架所需的某些专用类和接口的类。

POJO 名称用于强调给定对象是普通 Java 对象,而不是特殊对象,特别是不是 Enterprise JavaBean。

简单的 POJO 示例

基于上面提到的一些规则,我们可以定义一个 POJO 类,如下所示 -

public class Employee {
   private int id;
   private String firstName; 
   private String lastName;   
   private int salary;  

   public Employee() {}
   public Employee(String fname, String lname, int salary) {
      this.firstName = fname;
      this.lastName = lname;
      this.salary = salary;
   }
   
   public int getId() {
      return id;
   }
   
   public void setId( int id ) {
      this.id = id;
   }
   
   public String getFirstName() {
      return firstName;
   }
   
   public void setFirstName( String first_name ) {
      this.firstName = first_name;
   }
   
   public String getLastName() {
      return lastName;
   }
   
   public void setLastName( String last_name ) {
      this.lastName = last_name;
   }
   
   public int getSalary() {
      return salary;
   }
   
   public void setSalary( int salary ) {
      this.salary = salary;
   }
}

Hibernate - 映射文件

对象/关系映射通常在 XML 文档中定义。该映射文件指示 Hibernate — 如何将定义的一个或多个类映射到数据库表?

尽管许多 Hibernate 用户选择手动编写 XML,但是仍然有许多工具可以生成映射文档。其中包括针对高级 Hibernate 用户的XDoclet、MiddlegenAndroMDA 。

让我们考虑一下之前定义的 POJO 类,其对象将保留在下一节中定义的表中。

public class Employee {
   private int id;
   private String firstName; 
   private String lastName;   
   private int salary;  

   public Employee() {}
   
   public Employee(String fname, String lname, int salary) {
      this.firstName = fname;
      this.lastName = lname;
      this.salary = salary;
   }
   
   public int getId() {
      return id;
   }
   
   public void setId( int id ) {
      this.id = id;
   }
   
   public String getFirstName() {
      return firstName;
   }
   
   public void setFirstName( String first_name ) {
      this.firstName = first_name;
   }
   
   public String getLastName() {
      return lastName;
   }
   
   public void setLastName( String last_name ) {
      this.lastName = last_name;
   }
   
   public int getSalary() {
      return salary;
   }
   
   public void setSalary( int salary ) {
      this.salary = salary;
   }
}

将有一个表对应于您愿意提供持久性的每个对象。考虑以上对象需要存储和检索到以下 RDBMS 表中 -

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)
);

基于以上两个实体,我们可以定义以下映射文件,该文件指示 Hibernate 如何将定义的一个或多个类映射到数据库表。

<?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 = "Employee" table = "EMPLOYEE">
      
      <meta attribute = "class-description">
         This class contains the employee detail. 
      </meta>
      
      <id name = "id" type = "int" column = "id">
         <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>

您应该将映射文档保存在格式为 <classname>.hbm.xml 的文件中。我们将映射文档保存在 Employee.hbm.xml 文件中。

让我们了解一下映射文件中使用的映射元素的一些细节 -

  • 映射文档是一个以<hibernate-mapping>作为根元素的 XML 文档,其中包含所有<class>元素。

  • <class>元素用于定义从 Java 类到数据库表的特定映射Java 类名使用class 元素的name属性指定,数据库名使用 table 属性指定。

  • <meta>元素是可选元素,可用于创建类描述。

  • <id>元素将类中的唯一 ID 属性映射到数据库表的主键id元素的name属性指的是类中的属性,column属性指的是数据库表中的列。type属性保存hibernate映射类型,该映射类型将从Java转换为SQL数据类型

  • id 元素中的<generator>元素用于自动生成主键值。生成器元素的class属性设置为native ,让 hibernate可以根据底层数据库的功能选择identity、sequencehilo算法来创建主键。

  • <property>元素用于将 Java 类属性映射到数据库表中的列元素的name属性指的是类中的属性,column属性指的是数据库表的列。type属性保存hibernate映射类型,该映射类型将从Java转换为SQL数据类型

还有其他可用的属性和元素,这些属性和元素将在映射文档中使用,我会在讨论其他 Hibernate 相关主题时尝试尽可能多地介绍这些属性和元素。

Hibernate - 映射类型

当您准备 Hibernate 映射文档时,您会发现将 Java 数据类型映射到 RDBMS 数据类型。映射文件中声明和使用的类型不是Java 数据类型;它们也不是 SQL 数据库类型。这些类型称为Hibernate 映射类型,可以从 Java 数据类型转换为 SQL 数据类型,反之亦然。

本章列出了所有基本的、日期和时间、大对象以及各种其他内置映射类型。

原始类型

映射类型 Java类型 ANSI SQL 类型
整数 int 或 java.lang.Integer 整数
长的 long 或 java.lang.Long BIGINT
短的 Short 或 java.lang.Short 小智
漂浮 float 或 java.lang.Float 漂浮
双倍的 double 或 java.lang.Double 双倍的
大十进制 java.math.BigDecimal 数字
特点 java.lang.String 字符(1)
细绳 java.lang.String VARCHAR
字节 byte 或 java.lang.Byte 天音
布尔值 布尔值或 java.lang.Boolean 少量
是/否 布尔值或 java.lang.Boolean CHAR(1)(“Y”或“N”)
真假 布尔值或 java.lang.Boolean CHAR(1)(“T”或“F”)

日期和时间类型

映射类型 Java类型 ANSI SQL 类型
日期 java.util.Date 或 java.sql.Date 日期
时间 java.util.Date 或 java.sql.Time 时间
时间戳 java.util.Date 或 java.sql.Timestamp 时间戳
日历 java.util.日历 时间戳
日历日期 java.util.日历 日期

二进制和大对象类型

映射类型 Java类型 ANSI SQL 类型
二进制 字节[] VARBINARY(或 BLOB)
文本 java.lang.String CLOB
可序列化 任何实现 java.io.Serializable 的 Java 类 VARBINARY(或 BLOB)
块状 java.sql.Clob CLOB
斑点 java.sql.Blob BLOB

JDK相关类型

映射类型 Java类型 ANSI SQL 类型
班级 java.lang.Class VARCHAR
语言环境 java.util.Locale VARCHAR
时区 java.util.TimeZone VARCHAR
货币 java.util.Currency VARCHAR

Hibernate - 示例

现在让我们通过一个示例来了解如何使用 Hibernate 在独立应用程序中提供 Java 持久性。我们将介绍使用 Hibernate 技术创建 Java 应用程序所涉及的不同步骤。

创建 POJO 类

创建应用程序的第一步是构建一个或多个 Java POJO 类,具体取决于将保存到数据库的应用程序。让我们考虑使用getXXXsetXXX方法的Employee类,使其成为 JavaBeans 兼容类。

POJO(普通旧 Java 对象)是一种 Java 对象,它不扩展或实现 EJB 框架分别所需的一些专用类和接口。所有普通的 Java 对象都是 POJO。

当您设计一个由 Hibernate 持久化的类时,提供符合 JavaBeans 的代码以及一个属性非常重要,该属性将像Employee 类中的id属性一样充当索引。

public class Employee {
   private int id;
   private String firstName; 
   private String lastName;   
   private int salary;  

   public Employee() {}
   public Employee(String fname, String lname, int salary) {
      this.firstName = fname;
      this.lastName = lname;
      this.salary = salary;
   }
   
   public int getId() {
      return id;
   }
   
   public void setId( int id ) {
      this.id = id;
   }
   
   public String getFirstName() {
      return firstName;
   }
   
   public void setFirstName( String first_name ) {
      this.firstName = first_name;
   }
   
   public String getLastName() {
      return lastName;
   }
   
   public void setLastName( String last_name ) {
      this.lastName = last_name;
   }
   
   public int getSalary() {
      return salary;
   }
   
   public void setSalary( int salary ) {
      this.salary = salary;
   }
}

创建数据库表

第二步是在数据库中创建表。每个对象都会对应一个表,你愿意提供持久化。考虑以上对象需要存储和检索到以下 RDBMS 表中 -

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)
);

创建映射配置文件

这一步是创建一个映射文件,指示 Hibernate 如何将定义的一个或多个类映射到数据库表。

<?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 = "Employee" table = "EMPLOYEE">
      
      <meta attribute = "class-description">
         This class contains the employee detail. 
      </meta>
      
      <id name = "id" type = "int" column = "id">
         <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>

您应该将映射文档保存在格式为 <classname>.hbm.xml 的文件中。我们将映射文档保存在 Employee.hbm.xml 文件中。让我们看看有关映射文档的一些细节 -

  • 映射文档是一个以 <hibernate-mapping> 作为根元素的 XML 文档,其中包含所有 <class> 元素。

  • <class>元素用于定义从 Java 类到数据库表的特定映射Java 类名使用class 元素的name属性指定,数据库表名使用table属性指定。

  • <meta>元素是可选元素,可用于创建类描述。

  • <id> 元素将类中的唯一 ID 属性映射到数据库表的主键id元素的name属性指的是类中的属性,column属性指的是数据库表中的列。type属性保存hibernate映射类型,该映射类型将从Java转换为SQL数据类型

  • id 元素中的<generator>元素用于自动生成主键值。生成器元素的class属性设置为native,以便让 hibernate 选择标识、序列hilo算法来根据底层数据库的功能创建主键。

  • <property>元素用于将 Java 类属性映射到数据库表中的列元素的name属性指的是类中的属性,column属性指的是数据库表的列。type属性保存hibernate映射类型,该映射类型将从Java转换为SQL数据类型

还有其他可用的属性和元素,这些属性和元素将在映射文档中使用,我会在讨论其他 Hibernate 相关主题时尝试尽可能多地介绍这些属性和元素。

创建应用程序类

最后,我们将使用 main() 方法创建应用程序类来运行应用程序。我们将使用此应用程序保存一些员工记录,然后对这些记录应用 CRUD 操作。

import java.util.List; 
import java.util.Date;
import java.util.Iterator; 
 
import org.hibernate.HibernateException; 
import org.hibernate.Session; 
import org.hibernate.Transaction;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class ManageEmployee {
   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); 
      }
      
      ManageEmployee ME = new ManageEmployee();

      /* Add few employee records in database */
      Integer empID1 = ME.addEmployee("Zara", "Ali", 1000);
      Integer empID2 = ME.addEmployee("Daisy", "Das", 5000);
      Integer empID3 = ME.addEmployee("John", "Paul", 10000);

      /* List down all the employees */
      ME.listEmployees();

      /* Update employee's records */
      ME.updateEmployee(empID1, 5000);

      /* Delete an employee from the database */
      ME.deleteEmployee(empID2);

      /* List down new list of the employees */
      ME.listEmployees();
   }
   
   /* Method to CREATE an employee in the database */
   public Integer addEmployee(String fname, String lname, int salary){
      Session session = factory.openSession();
      Transaction tx = null;
      Integer employeeID = null;
      
      try {
         tx = session.beginTransaction();
         Employee employee = new Employee(fname, lname, salary);
         employeeID = (Integer) session.save(employee); 
         tx.commit();
      } catch (HibernateException e) {
         if (tx!=null) tx.rollback();
         e.printStackTrace(); 
      } finally {
         session.close(); 
      }
      return employeeID;
   }
   
   /* Method to  READ all the employees */
   public void listEmployees( ){
      Session session = factory.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(); 
      }
   }
   
   /* Method to UPDATE salary for an employee */
   public void updateEmployee(Integer EmployeeID, int salary ){
      Session session = factory.openSession();
      Transaction tx = null;
      
      try {
         tx = session.beginTransaction();
         Employee 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(); 
      }
   }
   
   /* Method to DELETE an employee from the records */
   public void deleteEmployee(Integer EmployeeID){
      Session session = factory.openSession();
      Transaction tx = null;
      
      try {
         tx = session.beginTransaction();
         Employee 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(); 
      }
   }
}

编译与执行

以下是编译和运行上述应用程序的步骤。在继续编译和执行之前,请确保您已正确设置 PATH 和 CLASSPATH。

  • 按照配置章节中的说明创建 hibernate.cfg.xml 配置文件。

  • 创建 Employee.hbm.xml 映射文件,如上所示。

  • 如上所示创建 Employee.java 源文件并编译它。

  • 如上所示创建 ManageEmployee.java 源文件并编译它。

  • 执行 ManageEmployee 二进制文件来运行该程序。

您将得到以下结果,并且将在 EMPLOYEE 表中创建记录。

$java ManageEmployee
.......VARIOUS LOG MESSAGES WILL DISPLAY HERE........

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 表,它应该有以下记录 -

mysql> select * from EMPLOYEE;
+----+------------+-----------+--------+
| id | first_name | last_name | salary |
+----+------------+-----------+--------+
| 29 | Zara       | Ali       |   5000 |
| 31 | John       | Paul      |  10000 |
+----+------------+-----------+--------+
2 rows in set (0.00 sec

mysql>

Hibernate - O/R 映射

到目前为止,我们已经看到了使用 hibernate 的非常基本的 O/R 映射,但是有三个最重要的映射主题,我们必须详细学习。

这些是 -

  • 集合映射,
  • 实体类之间关联的映射,以及
  • 组件映射。

集合映射

如果一个实体或类具有特定变量的值集合,那么我们可以使用 java 中可用的任何一个集合接口来映射这些值。Hibernate 可以持久保存java.util.Map、java.util.Set、java.util.SortedMap、java.util.SortedSet、java.util.List的实例以及任何持久实体或值的数组。

先生。 集合类型和映射说明
1 java.util.Set

这是使用 <set> 元素进行映射并使用 java.util.HashSet 进行初始化

2 java.util.SortedSet

它使用 <set> 元素进行映射,并使用 java.util.TreeSet 进行初始化。排序属性可以设置为比较器或自然排序

3 java.util.List

它使用 <list> 元素进行映射并使用 java.util.ArrayList 进行初始化

4 java.util.Collection

它使用 <bag> 或 <ibag> 元素进行映射,并使用 java.util.ArrayList 进行初始化

5 java.util.Map

这是使用 <map> 元素进行映射并使用 java.util.HashMap 进行初始化

6 java.util.SortedMap

它使用 <map> 元素进行映射并使用 java.util.TreeMap 进行初始化。排序属性可以设置为比较器或自然排序

Hibernate 支持数组,<primitive-array> 用于 Java 原始值类型,<array> 用于其他所有类型。然而,它们很少被使用,所以我不会在本教程中讨论它们。

如果你想映射一个用户定义的集合接口,而Hibernate不直接支持,你需要告诉Hibernate你的自定义集合的语义,这不是很容易,不推荐使用。

关联映射

实体类之间的关联和表之间的关系的映射是ORM的灵魂。以下是表达对象之间关系基数的四种方式。关联映射可以是单向的,也可以是双向的。

先生。 映射类型和描述
1 多对一

使用 Hibernate 映射多对一关系

2 一对一

使用 Hibernate 映射一对一关系

3 一对多

使用 Hibernate 映射一对多关系

4 多对多

使用 Hibernate 映射多对多关系

组件映射

实体类很可能可以将另一个类作为成员变量进行引用。如果被引用的类没有自己的生命周期,并且完全依赖于所属实体类的生命周期,那么被引用的类因此被称为组件

组件集合的映射也可以采用类似的方式,就像具有较小配置差异的常规集合的映射一样。我们将通过示例详细了解这两个映射。

先生。 映射类型和描述
1 组件映射

映射一个类,该类将另一个类的引用作为成员变量。

Hibernate - 注释

到目前为止,您已经了解了 Hibernate 如何使用 XML 映射文件将数据从 POJO 转换为数据库表,反之亦然。Hibernate 注释是无需使用 XML 文件即可定义映射的最新方法。您可以使用注释作为 XML 映射元数据的补充或替代。

Hibernate Annotations 是为对象和关系表映射提供元数据的强大方法。所有元数据都与代码一起放入 POJO java 文件中,这有助于用户在开发过程中同时了解表结构和 POJO。

如果您打算使您的应用程序可移植到其他符合 EJB 3 的 ORM 应用程序,则必须使用注释来表示映射信息,但如果您想要更大的灵活性,那么您应该使用基于 XML 的映射。

Hibernate 注解的环境设置

首先,您必须确保您使用的是 JDK 5.0,否则您需要将 JDK 升级到 JDK 5.0 才能利用对注释的本机支持。

其次,您需要安装 Hibernate 3.x 注释分发包,可从 sourceforge 获取:(下载 Hibernate Annotation)并复制hibernate-annotations.jar、lib/hibernate-comons-annotations.jarlib/ejb3-persistence。将 Hibernate Annotations 发行版中的jar 文件添加到您的 CLASSPATH 中。

带注释的类示例

正如我上面提到的,在使用 Hibernate Annotation 时,所有元数据都与代码一起合并到 POJO java 文件中,这有助于用户在开发过程中同时理解表结构和 POJO。

考虑我们将使用以下 EMPLOYEE 表来存储我们的对象 -

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)
);

以下是带有注释的 Employee 类的映射,以将对象与定义的 EMPLOYEE 表映射 -

import javax.persistence.*;

@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;  

   public Employee() {}
   
   public int getId() {
      return id;
   }
   
   public void setId( int id ) {
      this.id = id;
   }
   
   public String getFirstName() {
      return firstName;
   }
   
   public void setFirstName( String first_name ) {
      this.firstName = first_name;
   }
   
   public String getLastName() {
      return lastName;
   }
   
   public void setLastName( String last_name ) {
      this.lastName = last_name;
   }
   
   public int getSalary() {
      return salary;
   }
   
   public void setSalary( int salary ) {
      this.salary = salary;
   }
}

Hibernate 检测到 @Id 注释位于字段上,并假设它应该在运行时直接通过字段访问对象的属性。如果将 @Id 注释放在 getId() 方法上,则默认情况下将允许通过 getter 和 setter 方法访问属性。因此,所有其他注释也按照所选策略放置在字段或 getter 方法上。

以下部分将解释上述类中使用的注释。

@Entity注解

EJB 3 标准注释包含在javax.persistence包中,因此我们第一步导入该包。其次,我们对 Employee 类使用了@Entity注释,它将此类标记为实体 bean,因此它必须具有一个至少在受保护范围内可见的无参数构造函数。

@表注解

@Table 注释允许您指定将用于将实体保存在数据库中的表的详细信息。

@Table 注释提供了四个属性,允许您覆盖表的名称、目录和架构,并对表中的列强制执行唯一约束。目前,我们仅使用表名,即 EMPLOYEE。

@Id 和 @GenerateValue 注解

每个实体 bean 都有一个主键,您可以使用@Id注释在类上对其进行注释。主键可以是单个字段或多个字段的组合,具体取决于您的表结构。

默认情况下,@Id 注释将自动确定要使用的最合适的主键生成策略,但您可以通过应用 @GenerateValue 注释来覆盖它,注释采用两个参数策略生成器,我不会在这里讨论,所以让我们只使用默认的密钥生成策略。让 Hibernate 确定使用哪种生成器类型可以使您的代码在不同数据库之间移植。

@Column注解

@Column 注释用于指定字段或属性将映射到的列的详细信息。您可以将列注释与以下最常用的属性一起使用 -

  • name属性允许显式指定列的名称。

  • length属性允许用于映射值(特别是字符串值)的列的大小。

  • nullable属性允许在生成架构时将列标记为 NOT NULL。

  • unique属性允许将列标记为仅包含唯一值。

创建应用程序类

最后,我们将使用 main() 方法创建应用程序类来运行应用程序。我们将使用此应用程序保存一些员工记录,然后对这些记录应用 CRUD 操作。

import java.util.List; 
import java.util.Date;
import java.util.Iterator; 
 
import org.hibernate.Hibernat