【简明翻译】Hibernate 5.4 Getting Started Guide 官方入门文档

吃可爱长大的小学妹 提交于 2019-12-01 07:43:47

  前言

最近的精力主要集中在Hibernate上,在意识到Hibernate 5 的中文资料并不多的时候,我不得不把目光转向Hibernate的官方doc,学习之余简要翻一下入门文档。

原文地址:https://docs.jboss.org/hibernate/orm/5.4/quickstart/html_single/,勘误请在评论区留言

原文序

使用面向对象软件和关系型数据库可能既麻烦且耗时。开发成本往往会因数据在软件和数据库中的数据范式(paradigm)表现不一而显著地增长,Hibernate就是一种Java语言环境下的一个对象/关系映射 解决方案(ORM框架),对象/关系映射(ORM)的概念,则代指一种将数据的对象模型形式,即在软件中的表现形式,和数据模型形式,即数据库中的表现形式,这两种形式的数据相映射的技术。可以参照Wikipedia上的ORM词条以获得更详细的了解。

虽然Hibernate并不要求用户需要有非常丰富的SQL编程经验,但是对于一些概念的基本理解着实可以让你更快更全面的理解Hibernate,特别是对数据建模原理的理解就显得尤为重要,这两篇文章可以帮助你快速开始理解这些原理dataModeling101 、DataModeling(wiki)

Hibernate负责Java class和数据库表的映射工作,同时也会处理两者间数据格式的映射。另外,它还提供了数据查询和获取功能。它可以节省开发者原本需要的手动数据处理时间(如果你使用SQL和JDBC这些原生手段的话)Hibernate的设计目标是将开发者从95%的日常持久化编程步骤中解放出来,开发者再无需手册来通过SQL和JDBC手动处理数据。同时,不像其他持久化方案,Hibernate并不会将原生SQL的优点隐藏起来,你依旧可以使用它,意味着你之前所付出的学习和相关知识依然十分有价值。

HIbernate可能不是那些以数据为中心的,重度依赖存储过程的应用的最佳解决方案。它更适合于对于数据相关的应用中间层,这种情况下,它的确可以去除掉那些针对特定数据库而写的SQL,流水化查询的数据集转译到对象表(对于编程语言而言)。

See http://hibernate.org/orm/contribute/ for information on getting involved.

本文章中涉及的项目代码可以从这里下载: hibernate-tutorials.zip

  

1. 获取 Hibernate

1.1. Hibernate Modules/Artifacts

Hibernate’s 的功能被分成一些不同的 modules/artifacts 用来隔离依赖关系(模块化).

hibernate-core

Hibernate 核心module. 定义了ORM功能和API,还有不同的集成SPIs(方便第三方进行自定义扩展).

hibernate-envers

Hibernate历史实体版本控制功能

hibernate-spatial

Hibernate空间数据集和GIS(地理信息系统)数据类型支持

hibernate-osgi

Hibernate对在OSGi容器中运行的支持。

hibernate-agroal

Hibernate Agroal 连接池支持

hibernate-c3p0

Hibernate  C3P0 连接池支持

hibernate-hikaricp

Hibernate  HikariCP 连接池支持

hibernate-vibur

Hibernate  Vibur DBCP 连接池支持

hibernate-proxool

Hibernate  Proxool 连接池支持

hibernate-jcache

Hibernate JCache 缓存支持 , 使得任何兼容的组件成为二级缓存的提供者。

hibernate-ehcache

Hibernate Ehcache 缓存支持。使得Ehache成为二级缓存提供者。

 1.2. 发行包下载

Hibernate发行包存放在 SourceForge File Release System, 有 TGZ 和 ZIP 两种格式,两种都包含了JAR文件、文档、源代码和其他一些东西。

你可以从这里下载:https://sourceforge.net/projects/hibernate/files/hibernate-orm/. 以下是发行包目录结构:

  • lib/required/ 目录包含 hibernate-core jar包和它的依赖。所有的jar包都需要在在classpath下,不论那些功能有没有被用到。

  • lib/envers 目录包含 hibernate-envers jar包和它的依赖 (先包含lib/required/ 和 lib/jpa/).

  • lib/spatial/ 目录包含 hibernate-spatial jar包和它的依赖 (先包含 lib/required/)

  • lib/osgi/ 目录包含 hibernate-osgi jar包和它的依赖 (先包含 lib/required/ 和lib/jpa/)

  • lib/jpa-metamodel-generator/ 目录包含 生成Criteria API类型安全的元模型(Criteria API type-safe Metamodel)所需的jar。

  • lib/optional/ 目录包含 Hibernate提供的各种连接池和第二级缓存集成所需的jar及其依赖。

1.3. Maven Repository Artifacts

Hibernate artifacts的权威仓库为the JBoss Maven repository. Hibernate artifacts会自动同步到这上面(可能会延迟发布).

负责JBoss Maven仓库的团队维护着许多包含重要信息的Wiki页面:

Hibernate ORM artifacts发布在org.hibernate groupId下。

2. 使用Hibernate原生 API 和 hbm.xml 映射文件 

  本示例位于您下载的压缩包中的basic/.
 
 
目标
  • 启动 Hibernate SessionFactory

  • 使用 Hibernate 映射文件(hbm.xml)来提供映射信息

  • 使用Hibernate原生API

2.1. Hibernate配置文件

在本示例中,  hibernate.cfg.xml 文件定义了Hibernate配置信息

connection.driver_classconnection.urlconnection.username 和connection.password <property/> 元素定义了JDBC连接信息这些示例使用内置的H2 in-memory 数据库,所以所有的属性被设置成H2数据库以在内存中运行connection.pool_size 用来配置内置连接池的大小。

  内置的Hibernate连接池并不能用于实际应用中,对比实际应用中的的连接池它缺乏一些基本功能

 

dialect元素定义了Hibernate会使用的特定SQL类型

  绝大多数情况下, Hibernate 能够自动选择数据库的方言(dialect),当你使用多种数据库时这点尤其有用(注:3.x版本不清楚)

 

hbm2ddl.auto 属性开启自动生成数据库schema,也即自动建表功能。

最后,添加映射文件到配置文件中, 位于 <mapping/> 元素中的resource 使得Hibernate会尝试去使用用java.lang.ClassLoader 在classpath下进行查找。

有许多方式可以用于启动SessionFactory,详见the Native Bootstrapping topical guide. 

2.2. Java类

本示例中的实体类为示例代码中的: org.hibernate.tutorial.hbm.Event

关于实体类:
  • 实体类使用标准JavaBean的命名规范,包括getter/setter和私有的变量,虽然这是推荐的用法,但并不强制

  • 无参构造函数,同样作为JavaBean的规范,则要求必须实现,Hibernate需要通过反射机制(Java Reflection)为你创建实体类(即查询结果时),构造函数不能是私有的,同时,包可见性也要保证,这样才能通过java运行时代理机制(runtime proxy)生成以保证无需通过 字节码检测(bytecode instrumentation)进行代理。

2.3. 映射文件

本示例中的映射文件位于 org/hibernate/tutorial/hbm/Event.hbm.xml (同上文).

Hibernate 使用映射元数据来决定如何加载和存储持久化类,Hibernate 映射文件就是提供元数据的一种方式。

示例 1. 类映射元素
<class name="Event" table="EVENTS">
    ...
</class>

 关于 <varname>class</varname> 映射元素:

  • name 属性 (可在 <hibernate-mapping/> 中添加package属性来定义包名) 定义了类名

  • table 属性定义表名

到此为止,Event类和EVENTS数据库表被关联起来。

示例 2. Id映射
<id name="id" column="EVENT_ID">
    ...
</id>

 Hibernate 使用 <id/> 元素来确保行唯一性。

  id元素不需要映射到表的实际主键列,但这是常规约定。在Hibernate中映射的表甚至不需要定义主键。但是,强烈建议所有schema都定义适当的参照完整性。如此一来,id和主键在整个Hibernate中可以互换使用 。

 

此处的<id/> 元素将EVENT_ID列命名为EVENTS表的主键。它还将Event类的id属性标识为包含标识符值的属性。

 generator 元素通知Hibernate使用哪种策略为该实体生成主键值。本示例使用简单的递增计数。(注,在其他相关性能调优指南文章中,有提及不要使用id生成器,会那样会阻止批量插入)

示例 3. 属性映射元素
<property name="date" type="timestamp" column="EVENT_DATE"/>
<property name="title"/>

这两个 <property/>元素声明了Event 类的其余两个持久属性:date 和title 。date 属性映射包括列属性,但title 不包含。在没有列属性的情况下,Hibernate默认使用属性名称作为列名称。这适用于title,但是由于date 是大多数数据库中的保留关键字,因此您需要为列名指定一个非保留字。 

title映射也缺少类型属性。映射文件中声明和使用的类型既不是Java原生数据类型也不是SQL数据库类型。相反,它们是Hibernate映射类型,它们是在Java和SQL数据类型之间转换的转换器。如果未在映射中指定type属性,则Hibernate尝试自动确定正确的转换和映射类型,方法是使用Java反射来确定已声明属性的Java类型,并使用该Java类型的默认映射类型(注:如,BigInteger->Integer)。

在某些情况下,如date 属性所示,此自动检测可能未选择您期望或需要的默认值。 Hibernate无法知道类型为java.util.Date的属性是否应映射到SQL DATE,TIME或TIMESTAMP数据类型。通过将属性映射到timestamp转换器(timestamp converter)来保存完整的日期和时间信息,该转换器标识转换器类org.hibernate.type.TimestampType

  处理映射文件时,Hibernate使用反射来确定映射类型。此过程增加了时间和资源方面的开销。如果启动性能( startup performance)很重要,请考虑明确定义要使用的类型。

 

2.4. 示例代码

 org.hibernate.tutorial.hbm.NativeApiIllustrationTest 类说明了如何使用Hibernate原生API。

  为了易于使用,这些教程中的示例以JUnit测试的形式呈现。这种方法的优点之一是setUp() tearDown() 大致说明了如何在应用程序启动时创建org.hibernate.SessionFactory并在应用程序生命周期结束时将其关闭。
 
 
示例 4. 获取 org.hibernate.SessionFactory
protected void setUp() throws Exception {
    // A SessionFactory is set up once for an application!
    final StandardServiceRegistry registry = new StandardServiceRegistryBuilder()
            .configure() // configures settings from hibernate.cfg.xml
            .build();
    try {
        sessionFactory = new MetadataSources( registry ).buildMetadata().buildSessionFactory();
    }
    catch (Exception e) {
        // The registry would be destroyed by the SessionFactory, but we had trouble building the SessionFactory
        // so destroy it manually.
        StandardServiceRegistryBuilder.destroy( registry );
    }
} 

setUp方法首先创建org.hibernate.boot.registry.StandardServiceRegistry实例,该实例将配置信息合并到服务(Services,有特指)的工作集中以供SessionFactory使用。在本教程中,我们在hibernate.cfg.xml中定义了所有配置信息。

使用StandardServiceRegistry我们创建org.hibernate.boot.MetadataSources,这是向Hibernate告知您的Domain模型的起点。再一次,因为我们在hibernate.cfg.xml中定义了它,所以这边没什么东西好讲的。 org.hibernate.boot.Metadata表示SessionFactory将基于的应用程序域模型的完整,部分验证的视图。

引导程序的最后一步是构建SessionFactory。 SessionFactory是一个线程安全的对象,实例化一次即可服务整个应用程序。

SessionFactory充当org.hibernate.Session实例的工厂,应将其视为“工作单元”的必然(corollary )结果。

示例 5. 保存实体

Session session = sessionFactory.openSession();
session.beginTransaction();
session.save( new Event( "Our very first event!", new Date() ) );
session.save( new Event( "A follow up event", new Date() ) );
session.getTransaction().commit();
session.close();

testBasicUsage() 首先使用save() 方法创建一些新的Event对象并将其交给Hibernate进行管理。 Hibernate现在负责为每个Event在数据库上执行INSERT。 

示例 6. 获取List结果集
session = sessionFactory.openSession();
session.beginTransaction();
List result = session.createQuery( "from Event" ).list();
for ( Event event : (List<Event>) result ) {
    System.out.println( "Event (" + event.getDate() + ") : " + event.getTitle() );
}
session.getTransaction().commit();
session.close();

 在这里,我们看到一个Hibernate查询语言(HQL)的示例,该示例通过生成适当的SELECT SQL,将其发送到数据库,并使用结果集数据填充Event对象来从数据库加载所有现有的Event对象。

2.5. 下一步!

练习
  • 重新配置示例以连接到您自己的持久关系数据库。 

  •  Add an association to the Event entity to model a message thread.

3. 使用 Hibernate 原生API 和 注解式映射

  本示例位于您下载的压缩包中的 annotations/.
 
 
目标:
  • 启动 Hibernate SessionFactory

  • 使用 Java注解来提供映射信息

  • 使用Hibernate原生API

3.1. Hibernate配置文件

内容与上文的Hibernate配置文件相同,但有一个重要区别...最后的<mapping />元素使用class属性命名带注释的实体类。

3.2. 注解的Java类

本示例中的实体类是遵循JavaBean约定的org.hibernate.tutorial.annotations.Event。实际上,该类本身与实体Java类中的类相同,只不过注释用于提供元数据而不是单独的映射文件。

示例7.将类标识为实体
@Entity
@Table( name = "EVENTS" )
public class Event {
    ...
}

 @ javax.persistence.Entity注释用于将类标记为实体。它的功能与映射文件中讨论的<class />映射元素相同。此外,@ javax.persistence.Table注释显式指定了表名。如果没有此规范,默认表名称将为EVENT。

示例8. 标记id属性

@Id
@GeneratedValue(generator="increment")
@GenericGenerator(name="increment", strategy = "increment")
public Long getId() {
    return id;
}

@ javax.persistence.Id标记定义实体标识符的属性。

@ javax.persistence.GeneratedValue@ org.hibernate.annotations.GenericGenerator协同工作以指定Hibernate应该对该实体的标识符值使用Hibernate的增量生成策略。

示例9. 标记基本属性
public String getTitle() {
    return title;
}

@Temporal(TemporalType.TIMESTAMP)
@Column(name = "EVENT_DATE")
public Date getDate() {
    return date;
}

与映射文件中一样,日期属性需要进行特殊处理以考虑其特殊命名和SQL类型。 带有注释的映射默认情况下将实体的属性视为持久化属性(与数据库字段相同),这就是为什么我们看不到任何与title相关的映射信息的原因。 

3.3. 示例代码

org.hibernate.tutorial.annotations.AnnotationsIllustrationTest本质上与示例代码中讨论的org.hibernate.tutorial.hbm.NativeApiIllustrationTest相同。

3.4. 下一步!

练习
  • 向事件实体添加关联以对消息线程进行建模。有关更多详细信息,请使用《用户指南》。 

  • 添加回调以在创建,更新或删除事件时接收通知。使用事件监听器尝试相同的操作。有关更多详细信息,请使用《用户指南》。

4. 使用 Java Persistence API (JPA)

  本示例位于您下载的压缩包中的 entitymanager/.
 
 
目标:
  • 启动JPA EntityManagerFactory 

  • 使用 Java注解来提供映射信息

  • 使用JPA API 

4.1. persistence.xml

之前的教程使用了特定于Hibernate的hibernate.cfg.xml配置文件。但是,JPA定义了一个不同的引导过程,该过程使用其自己的名为persistence.xml的配置文件。该引导过程由JPA规范定义。在Java SE环境中,需要持久性提供程序(在这种情况下为Hibernate)通过META-INF / persistence.xml资源名称的类路径查找来定位所有JPA配置文件。

示例10. persistence.xml
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
        version="2.0">
    <persistence-unit name="org.hibernate.tutorial.jpa">
        ...
    </persistence-unit>
</persistence>

persistence.xml文件应为每个“持久性单元”提供唯一的名称。在获取javax.persistence.EntityManagerFactory引用时,应用程序使用此名称来引用配置。

Hibernate配置文件中讨论了<properties />元素中定义的设置。这里尽可能使用javax.persistence前缀的变体。请注意,其余特定于Hibernate的配置设置名称现在以hibernate前缀。

此外,<class />元素的功能与我们在Hibernate配置文件中看到的相同。

4.2. 注解的Java类

实体与上节注解的的Java类中的完全相同。

4.3. 示例代码

先前的教程使用了Hibernate原生API。本教程使用JPA API

示例11. 获取 javax.persistence.EntityManagerFactory
protected void setUp() throws Exception {
    sessionFactory = Persistence.createEntityManagerFactory( "org.hibernate.tutorial.jpa" );
}

再次注意,持久化单元名称是org.hibernate.tutorial.jpa,与persistence.xml相匹配。

示例12. 保存实体类
EntityManager entityManager = sessionFactory.createEntityManager();
entityManager.getTransaction().begin();
entityManager.persist( new Event( "Our very first event!", new Date() ) );
entityManager.persist( new Event( "A follow up event", new Date() ) );
entityManager.getTransaction().commit();
entityManager.close();

该代码类似于上文的保存实体类。使用javax.persistence.EntityManager接口代替org.hibernate.Session接口。 JPA将此操作称为“持久化”(persistence)而不是“保存”(save)。

示例13. 获取List结果集
entityManager = sessionFactory.createEntityManager();
entityManager.getTransaction().begin();
List<Event> result = entityManager.createQuery( "from Event", Event.class ).getResultList();
for ( Event event : result ) {
    System.out.println( "Event (" + event.getDate() + ") : " + event.getTitle() );
}
entityManager.getTransaction().commit();
entityManager.close();

同样,该代码与我们在获取上文的 获取List结果集看到的非常相似。

4.4. 下一步!

练习
  • 开发一个EJB Session bean来研究使用容器管理的持久性上下文的含义。尝试无状态(stateless )和有状态(stateful )两种情况。 

  • 将事件监听器(listeners)与基于CDI的注入(CDI-based injection)结合使用,以开发基于JMS的事件消息中心 

5. 使用 Envers

  本示例位于您下载的压缩包中的 envers/.
 
 
目标
  • 将实体注释为历史对象
  •  配置 Envers

  • 使用Envers API查看和分析历史数据

5.1. persistence.xml

这个文件在JPA 示例中已提过 persistence.xml, 而且基本是一样的

5.2. 注解的Java类

同样,该实体与上文:注释的Java类中的相同。主要区别在于添加了@ org.hibernate.envers.Audted注释,该注释告诉Envers自动跟踪对此实体的更改。

5.3. 示例代码

该代码保存了一些实体,对其中一个实体进行了更改,然后使用Envers API来查询初始修订(revision)以及更新的修订。修订是指实体的历史快照(snapshot )。

示例14. 使用org.hibernate.envers.AuditReader
public void testBasicUsage() {
    ...
    AuditReader reader = AuditReaderFactory.get( entityManager );
    Event firstRevision = reader.find( Event.class, 2L, 1 );
    ...
    Event secondRevision = reader.find( Event.class, 2L, 2 );
    ...
}

可以看到:我们从org.hibernate.envers.AuditReaderFactory获得了一个org.hibernate.envers.AuditReader,它包装了javax.persistence.EntityManager。 

接下来,find 方法检索实体的特定修订版。第一次调用找到ID为2的事件的修订版本1。第二次调用找到ID为2的事件的修订版本2。

5.4.下一步!

练习
  • 提供自定义修订版本实体,以额外获取进行更改的人员。 

  •  写一个只取回符合条件历史数据的查询。 使用 User Guide 查看 Envers 查询如何创建。(Envers用于在自动生成记录更改信息的数据表,用于审计)

  • 尝试使用具有各种关系(多对一,多对多等)的审计实体(auditing entities)。尝试查找此类实体的历史版本(修订版)并浏览对象树。
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!