update the QuickStart guide (#6807)

* update the code examples in the quickstart

* update the quickstart document

* slightly restructure the quickstart document
This commit is contained in:
Gavin King 2023-06-15 23:52:49 +02:00 committed by GitHub
parent 126207bbfe
commit 7cf4fd0626
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 576 additions and 912 deletions

View File

@ -114,7 +114,7 @@ tasks.register('renderTopicalGuides', AsciidoctorTask) { task ->
tasks.register('renderGettingStartedGuides', AsciidoctorTask) { task ->
group = "Documentation"
description = 'Renders the Getting Started Guides (quick starts) in HTML format using Asciidoctor.'
description = 'Renders the Getting Started Guides (quickstarts) in HTML format using Asciidoctor.'
tasks.buildDocs.dependsOn task
tasks.buildDocsForPublishing.dependsOn task
inputs.property "hibernate-version", project.ormVersion
@ -124,8 +124,41 @@ tasks.register('renderGettingStartedGuides', AsciidoctorTask) { task ->
include 'index.adoc'
}
outputDir = new File("$buildDir/asciidoc/quickstart/html_single")
attributes linkcss: true,
stylesheet: "css/hibernate.css",
docinfo: 'private',
jpaJavadocUrlPrefix: "https://javaee.github.io/javaee-spec/javadocs/javax/persistence/"
resources {
from('src/main/style/asciidoctor') {
include 'images/**'
}
from('src/main/style/asciidoctor') {
include 'css/**'
}
from('src/main/style/asciidoctor') {
include 'js/**'
}
}
}
tasks.register('renderGettingStartedGuidesPdf', AsciidoctorPdfTask) {task->
group = "Documentation"
description = 'Renders the Getting Started Guides in PDF format using Asciidoctor.'
tasks.buildDocs.dependsOn task
tasks.buildDocsForPublishing.dependsOn task
inputs.property "hibernate-version", project.ormVersion
sourceDir = file( 'src/main/asciidoc/quickstart/guides' )
baseDir = file( 'src/main/asciidoc/quickstart/guides' )
sources {
include 'index.adoc'
}
outputDir = "$buildDir/asciidoc/quickstart/pdf"
attributes jpaJavadocUrlPrefix: "https://javaee.github.io/javaee-spec/javadocs/javax/persistence/"
}
tasks.register('buildTutorialZip', Zip) { task ->
from 'src/main/asciidoc/quickstart/tutorials'
@ -133,7 +166,7 @@ tasks.register('buildTutorialZip', Zip) { task ->
archiveFileName = 'hibernate-tutorials.zip'
expand(
version: project.version,
slf4j: "1.7.5",
slf4j: "2.0.7",
junit: testLibs.versions.junit4.get(),
h2: dbLibs.versions.h2.get()
)

View File

@ -1,14 +1,17 @@
= Hibernate Getting Started Guide
:pdf-theme: ../../pdf/theme.yml
:source-highlighter: rouge
:icons: font
:doctype: book
:pdf-fontsdir: ../../pdf/fonts
= Getting Started with Hibernate
:title-logo-image: image:../../../style/asciidoctor/images/org/hibernate/logo.png[]
:toc:
:docinfo:
include::preface.adoc[]
:numbered:
include::obtaining.adoc[]
include::tutorial_native.adoc[]
include::tutorial_annotations.adoc[]
include::tutorial_jpa.adoc[]

View File

@ -1,54 +1,109 @@
[[introduction]]
== Introduction
Hibernate is an _Object/Relational Mapping_ (ORM) solution for programs written in Java and other JVM languages.
It lets us map Java classes to database tables, and fields of the Java classes to columns of the tables, and then
takes over the most tedious work involved in executing SQL statements against the database. Hibernate typically
eliminates upward of 90% of the work involved in common persistence-related programming tasks.
However, unlike some other persistence solutions, Hibernate doesn't attempt to hide the relational model, nor take
away the power of SQL as a query language. On the contrary, Hibernate centers the relational data, makes it visible
to Java in a natural and typesafe object-oriented form, and offers an extremely powerful SQL-like query language for
working with the data in Java.
[NOTE]
Hibernate may not be the best solution for data-centric applications where business logic is implemented in stored
procedures. Hibernate is most useful for programs with an object-oriented domain model and business logic in a
Java-based _middle tier_.
[[resources]]
.Resources
****
A strong background in SQL is not required to use Hibernate, at least not at first, but a basic understanding of the
concepts is important.
An understanding of _data modeling_ principles is especially important.
Good starting points include:
- https://www.agiledata.org/essays/dataModeling101.html[Data Modeling 101], and
- https://en.wikipedia.org/wiki/Data_modeling[Wikipedia].
If you're completely new to database access in Java, a decent overview of various technologies and options and how they
fit together may be found at:
- https://www.marcobehler.com/guides/a-guide-to-accessing-databases-in-java[Java & Databases: An Overview of Libraries & APIs].
This guide will help you get up and running with Hibernate itself.
But the best way to start learning Hibernate properly is the _Introduction to Hibernate 6_, available at
https://hibernate.org/orm/documentation[the same place you got this document].
[TIP]
====
Of course, the other essential resource will be the documentation for your RDBMS, and especially the guide to the dialect
of SQL provided by your database.
====
****
[[obtaining]]
== Obtaining Hibernate
=== Obtaining Hibernate
=== The Hibernate Modules/Artifacts
We may obtain any Hibernate module we need just by declaring a dependency on the module in our Maven or Gradle build.
We're certainly going to need `hibernate-core`, so we'll go ahead and declare a dependency on `org.hibernate.orm:hibernate-core`.
Hibernate's functionality is split into a number of modules/artifacts meant to isolate dependencies (modularity).
In Gradle we would have:
hibernate-core:: The main (core) Hibernate module. Defines its ORM features and APIs as well as the various integration SPIs.
hibernate-envers:: Hibernate's historical entity versioning feature
hibernate-spatial:: Hibernate's Spatial/GIS data-type support
hibernate-agroal:: Integrates the https://agroal.github.io/[Agroal] connection pooling library into Hibernate
hibernate-c3p0:: Integrates the https://www.mchange.com/projects/c3p0/[C3P0] connection pooling library into Hibernate
hibernate-hikaricp:: Integrates the https://github.com/brettwooldridge/HikariCP/[HikariCP] connection pooling library into Hibernate
hibernate-vibur:: Integrates the https://www.vibur.org/[Vibur DBCP] connection pooling library into Hibernate
hibernate-proxool:: Integrates the https://proxool.sourceforge.net/[Proxool] connection pooling library into Hibernate
hibernate-jcache:: Integrates the https://jcp.org/en/jsr/detail?id=107$$[JCache] caching specification into Hibernate,
enabling any compliant implementation to become a second-level cache provider.
hibernate-community-dialects:: Hibernate's community supported dialects
hibernate-graalvm:: Experimental extension to make it easier to compile applications into a https://www.graalvm.org/[GraalVM] native image
hibernate-micrometer:: Integration for Micrometer metrics into Hibernate as a metrics collection package
hibernate-testing:: Support for testing Hibernate ORM functionality
hibernate-integrationtest-java-modules:: Integration tests for running Hibernate ORM in the Java module path
[source,groovy]
----
implementation 'org.hibernate.orm:hibernate-core:6.3.0.Final'
----
=== Release Bundle Downloads
Or in Maven:
The Hibernate team provides release bundles hosted on the SourceForge File Release System, in both
`TGZ` and `ZIP` formats. Each release bundle contains `JAR` files, documentation, source code, and other goodness.
[source,xml]
----
<dependency>
<groupId>org.hibernate.org</groupId>
<artifactId>hibernate-core</artifactId>
<version>6.3.0.Final</version>
</dependency>
----
You can download releases of Hibernate, in your chosen format, from the list at
https://sourceforge.net/projects/hibernate/files/hibernate-orm/. The release bundle is structured as follows:
[[modules]]
=== Modules belonging to Hibernate ORM
* The `lib/required/` directory contains the `hibernate-core` jar and all of its dependencies. All of these jars are
required to be available on your classpath no matter which features of Hibernate are being used.
* The `lib/envers` directory contains the `hibernate-envers` jar and all of its dependencies (beyond those in
`lib/required/` and `lib/jpa/`).
* The `lib/spatial/` directory contains the `hibernate-spatial` jar and all of its dependencies (beyond those in `lib/required/`)
* The `lib/jpa-metamodel-generator/` directory contains the jar needed for generating the Criteria API type-safe Metamodel.
* The `lib/optional/` directory contains the jars needed for the various connection pooling and second-level cache integrations
provided by Hibernate, along with their dependencies.
Hibernate ORM is an umbrella project containing the following modules:
=== Maven Repository Artifacts
[cols="40m,~"]
.API-oriented modules
|===
|hibernate-core| The core object/relational mapping engine
|hibernate-envers| Entity versioning and auditing
|hibernate-spatial| Support for spatial/GIS data types
|hibernate-jpamodelgen| An annotation processor that generates a JPA-compliant metamodel
|===
The authoritative repository for Hibernate artifacts is the JBoss Maven repository. The Hibernate artifacts are
synced to Maven Central as part of an automated job (some small delay may occur).
[cols="40m,~"]
.Integration-oriented modules
|===
|hibernate-agroal| Support for https://agroal.github.io/[Agroal] connection pooling
|hibernate-c3p0| Support for https://www.mchange.com/projects/c3p0/[C3P0] connection pooling
|hibernate-hikaricp| Support for https://github.com/brettwooldridge/HikariCP/[HikariCP] connection pooling
|hibernate-vibur| Support for https://www.vibur.org/[Vibur DBCP] connection pooling
|hibernate-proxool| Support for https://proxool.sourceforge.net/[Proxool] connection pooling
|hibernate-jcache| Integration with https://jcp.org/en/jsr/detail?id=107$$[JCache], allowing any compliant implementation as a second-level cache provider
|hibernate-community-dialects| Additional community-supported SQL dialects
|hibernate-graalvm| Experimental extension to make it easier to compile applications as a https://www.graalvm.org/[GraalVM] native image
|hibernate-micrometer| Integration with https://micrometer.io[Micrometer] metrics
|===
The team responsible for the JBoss Maven repository maintains a number of Wiki pages that contain important information:
[cols="40m,~"]
.Testing-oriented modules
|===
|hibernate-testing| A framework for testing Hibernate ORM functionality
|hibernate-integrationtest-java-modules| Integration tests for running Hibernate ORM in the Java module path
|===
* https://community.jboss.org/docs/DOC-14900 - General information about the repository.
* https://community.jboss.org/docs/DOC-15170 - Information about setting up the JBoss repositories in order to do
development work on JBoss projects themselves.
* https://community.jboss.org/docs/DOC-15169 - Information about setting up access to the repository to use JBoss
projects as part of your own software.
These artifacts are published under the Maven group id `org.hibernate.orm`.
[NOTE]
There's more to Hibernate than the modules belonging to the ORM project: Hibernate Search, Hibernate Reactive, Hibernate Validator, and more.
The Hibernate ORM artifacts are published under the `org.hibernate` groupId.

View File

@ -1,38 +0,0 @@
[[preface]]
[preface]
== Preface
Working with both Object-Oriented software and Relational Databases can be cumbersome and time-consuming.
Development costs are significantly higher due to a number of "paradigm mismatches" between how data is represented in objects
versus relational databases. Hibernate is an Object/Relational Mapping (ORM) solution for Java environments. The
term Object/Relational Mapping refers to the technique of mapping data between an object model representation to
a relational data model representation. See https://en.wikipedia.org/wiki/Object-relational_mapping for a good
high-level discussion. Also, Martin Fowler's link:$$https://martinfowler.com/bliki/OrmHate.html$$[OrmHate] article
takes a look at many of the mismatch problems.
Although having a strong background in SQL is not required to use Hibernate, having a basic understanding of the
concepts can help you understand Hibernate more quickly and fully. An understanding of data modeling principles
is especially important. Both https://www.agiledata.org/essays/dataModeling101.html and
https://en.wikipedia.org/wiki/Data_modeling are good starting points for understanding these data modeling
principles. If you are completely new to database access in Java,
https://www.marcobehler.com/guides/a-guide-to-accessing-databases-in-java contains a good overview of the various parts,
pieces and options.
Hibernate takes care of the mapping from Java classes to database tables, and from Java data types to SQL data
types. In addition, it provides data query and retrieval facilities. It can significantly reduce development
time otherwise spent with manual data handling in SQL and JDBC. Hibernates design goal is to relieve the
developer from 95% of common data persistence-related programming tasks by eliminating the need for manual,
hand-crafted data processing using SQL and JDBC. However, unlike many other persistence solutions, Hibernate
does not hide the power of SQL from you and guarantees that your investment in relational technology and
knowledge is as valid as always.
Hibernate may not be the best solution for data-centric applications that only use stored-procedures to
implement the business logic in the database, it is most useful with object-oriented domain models and business
logic in the Java-based middle-tier. However, Hibernate can certainly help you to remove or encapsulate
vendor-specific SQL code and streamlines the common task of translating result sets from a tabular
representation to a graph of objects.
See https://hibernate.org/orm/contribute/ for information on getting involved.
IMPORTANT: The projects and code for the tutorials referenced in this guide are available as link:hibernate-tutorials.zip[]

View File

@ -1,104 +1,208 @@
[[tutorial_annotations]]
== Tutorial Using Native Hibernate APIs and Annotation Mappings
NOTE: This tutorial is located within the download bundle under `annotations/`.
== Tutorial using native Hibernate APIs
.Objectives
- [*] Bootstrap a Hibernate `SessionFactory`
- [*] Configure Hibernate using `hibernate.properties`
- [*] Create a `SessionFactory` using `org.hibernate.boot`
- [*] Use annotations to provide mapping information
- [*] Use the Hibernate native APIs
- [*] Use `Session` to persist and query data
****
This tutorial is located within the download bundle under `annotations/`.
****
[[hibernate-gsg-tutorial-annotations-config]]
=== The Hibernate configuration file
=== Configuration via properties file
The contents are identical to <<hibernate-gsg-tutorial-basic-config>> with one important difference...
The `<mapping/>` element at the very end naming the annotated entity class using the `class` attribute.
In this example, configuration properties are specified in a file named `hibernate.properties`.
.Configuration via `hibernate.properties`
[source,properties]
----
# Database connection settings
hibernate.connection.url=jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1
hibernate.connection.username=sa
hibernate.connection.password=
# Echo all executed SQL to console
hibernate.show_sql=true
hibernate.format_sql=true
hibernate.highlight_sql=true
# Automatically export the schema
hibernate.hbm2ddl.auto=create
----
The following properties specify JDBC connection information:
.JDBC connection settings
[%breakable,cols="35,~"]
|===
| Configuration property name | Purpose
| `jakarta.persistence.jdbc.url` | JDBC URL of your database
| `jakarta.persistence.jdbc.user` and `jakarta.persistence.jdbc.password` | Your database credentials
|===
[NOTE]
These tutorials use the H2 embedded database, so the values of these properties are specific to running H2 in its in-memory mode.
These properties enable logging of SQL to the console as it is executed, in an aesthetically pleasing format:
.Settings for SQL logging to the console
[%breakable,cols="35,~"]
|===
| Configuration property name | Purpose
| `hibernate.show_sql` | If `true`, log SQL directly to the console
| `hibernate.format_sql` | If `true`, log SQL in a multiline, indented format
| `hibernate.highlight_sql` | If `true`, log SQL with syntax highlighting via ANSI escape codes
|===
When developing persistence logic with Hibernate, it's very important to be able to see exactly what SQL is being executed.
[[hibernate-gsg-tutorial-annotations-entity]]
=== The annotated entity Java class
The entity class in this tutorial is `org.hibernate.tutorial.annotations.Event` which follows JavaBean conventions.
In fact the class itself is identical to the one in <<hibernate-gsg-tutorial-basic-entity>>, except that annotations
are used to provide the metadata, rather than a separate mapping file.
The entity class in this tutorial is `org.hibernate.tutorial.annotations.Event`.
Observe that:
- This class uses standard JavaBean naming conventions for property getter and setter methods, as well as private visibility for the fields.
This is recommended, but it's not a requirement.
- The no-argument constructor, which is also a JavaBean convention, _is_ a requirement for all persistent classes.
Hibernate needs to instantiate objects for you, using Java Reflection.
The constructor should have package-private or `public` visibility, to allow Hibernate to generate proxies and optimized code for field access.
We use annotations to identify the class as an entity, and to map it to the relational schema.
[[hibernate-gsg-tutorial-annotations-entity-entity]]
.Identifying the class as an entity
====
[source, JAVA]
[source, java]
----
@Entity
@Table( name = "EVENTS" )
@Entity <1>
@Table(name = "Events") <2>
public class Event {
...
}
----
====
The `@jakarta.persistence.Entity` annotation is used to mark a class as an entity. It functions the same as the
`<class/>` mapping element discussed in <<hibernate-gsg-tutorial-basic-mapping>>. Additionally the
`@jakarta.persistence.Table` annotation explicitly specifies the table name. Without this specification, the default
table name would be _EVENT_.
<1> `@jakarta.persistence.Entity` marks the `Event` class as an entity.
<2> `@jakarta.persistence.Table` explicitly specifies the name of the mapped table.
Without this annotation, the table name would default to `Event`.
Every entity class must have an identifier.
[[hibernate-gsg-tutorial-annotations-entity-id]]
.Identifying the identifier property
====
[source, JAVA]
[source, java]
----
@Id
@GeneratedValue(generator="increment")
@GenericGenerator(name="increment", strategy = "increment")
public Long getId() {
return id;
}
@Id <1>
@GeneratedValue <2>
private Long id;
----
====
`@jakarta.persistence.Id` marks the property which defines the entity's identifier.
`@jakarta.persistence.GeneratedValue` and `@org.hibernate.annotations.GenericGenerator` work in tandem
to indicate that Hibernate should use Hibernate's `increment` generation strategy for this entity's identifier values.
<1> `@jakarta.persistence.Id` marks the field as holding the identifier (primary key) of the entity.
<2> `@jakarta.persistence.GeneratedValue` specifies that this is a _synthetic id_, that is, a system-generated identifier (a surrogate primary key).
Other fields of the entity are considered persistent by default.
[[hibernate-gsg-tutorial-annotations-entity-properties]]
.Identifying basic properties
====
[source, JAVA]
.Mapping basic properties
[source, java]
----
public String getTitle() {
return title;
}
private String title;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "EVENT_DATE")
public Date getDate() {
return date;
}
@Column(name = "eventDate") <1>
private LocalDateTime date;
----
====
As in <<hibernate-gsg-tutorial-basic-mapping>>, the `date` property needs special handling to account for its special
naming and its SQL type.
Attributes of an entity are considered persistent by default when mapping with annotations, which is why we don't see
any mapping information associated with `title`.
<1> `@jakarta.persistence.Column` explicitly specifies the name of a mapped column.
Without this annotation, the column name would default to `date`, which is a keyword on some databases.
[[hibernate-gsg-tutorial-annotations-test]]
=== Example code
`org.hibernate.tutorial.annotations.AnnotationsIllustrationTest` is essentially the same as
`org.hibernate.tutorial.hbm.NativeApiIllustrationTest` discussed in <<hibernate-gsg-tutorial-basic-test>>.
The class `org.hibernate.tutorial.annotations.HibernateIllustrationTest` illustrates the use of the Hibernate's native APIs, including:
- `Session` and `SessionFactory`, and
- `org.hibernate.boot` for configuration and bootstrap.
There are several different ways to configure and start Hibernate, and this is not even the most common approach.
[NOTE]
The examples in these tutorials are presented as JUnit tests.
A benefit of this approach is that `setUp()` and `tearDown()` roughly illustrate how a `org.hibernate.SessionFactory` is
created when the program starts, and closed when the program terminates.
[[hibernate-gsg-tutorial-basic-test-setUp]]
.Obtaining the `SessionFactory`
[source, java]
----
protected void setUp() {
// A SessionFactory is set up once for an application!
final StandardServiceRegistry registry =
new StandardServiceRegistryBuilder()
.build(); <1> <2>
try {
sessionFactory =
new MetadataSources(registry) <3>
.addAnnotatedClass(Event.class) <4>
.buildMetadata() <5>
.buildSessionFactory(); <6>
}
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);
}
}
----
<1> The `setUp()` method first builds a `StandardServiceRegistry` instance which incorporates configuration information into a working set of `Services` for use by the `SessionFactory`.
<2> Here we put all configuration information in `hibernate.properties`, so there's not much interesting to see.
<3> Using the `StandardServiceRegistry` we create the `MetadataSources` which lets us tell Hibernate about our domain model.
<4> Here we have only one entity class to register.
<5> An instance of `Metadata` represents a complete, partially-validated view of the application domain model.
<6> The final step in the bootstrap process is to build a `SessionFactory` for the configured services and validated domain model.
The `SessionFactory` is a thread-safe object that's instantiated once to serve the entire application.
The `SessionFactory` produces instances of `Session`.
Each session should be thought of as representing a _unit of work_.
[[hibernate-gsg-tutorial-basic-test-saving]]
.Persisting entities
[source, java]
----
sessionFactory.inTransaction(session -> { <1>
session.persist(new Event("Our very first event!", now())); <2>
session.persist(new Event("A follow up event", now()));
});
----
<1> The `inTransaction()` method creates a session and starts a new transaction.
<2> Here we create two new `Event` objects and hands them over to Hibernate, calling the `persist()` method to make these instances persistent.
Hibernate is responsible for executing an `INSERT` statement for each `Event`.
[[hibernate-gsg-tutorial-basic-test-list]]
.Obtaining a list of entities
[source, java]
----
sessionFactory.inTransaction(session -> {
session.createSelectionQuery("from Event", Event.class) <1>
.getResultList() <2>
.forEach(event -> out.println("Event (" + event.getDate() + ") : " + event.getTitle()));
});
----
<1> Here we use a very simple _Hibernate Query Language_ (HQL) statement to load all existing `Event` objects from the database.
<2> Hibernate generates and executes the appropriate `SELECT` statement, and then instantiates and populates `Event` objects with the data in the query result set.
[[hibernate-gsg-tutorial-annotations-further]]
=== Take it further!
.Practice Exercises
- [ ] Add an association to the `Event` entity to model a message thread. Use the
https://docs.jboss.org/hibernate/orm/current/userguide/html_single/Hibernate_User_Guide.html[_User Guide_] for more details.
- [ ] Add a callback to receive notifications when an `Event` is created, updated or deleted.
Try the same with an event listener. Use the
https://docs.jboss.org/hibernate/orm/current/userguide/html_single/Hibernate_User_Guide.html[_User Guide_] for more details.
- [ ] Actually run this example to see the SQL executed by Hibernate displayed in the console.
- [ ] Reconfigure the examples to connect to your own persistent relational database.
- [ ] Add an association to the `Event` entity to model a message thread.
See the _Introduction to Hibernate 6_ for details.

View File

@ -1,27 +1,25 @@
[[tutorial_envers]]
== Tutorial Using Envers
NOTE: This tutorial is located within the download bundle under `envers/`.
.Objectives
- [*] Annotate an entity as historical
- [*] Configure Envers
- [*] Use the Envers APIs to view and analyze historical data
****
This tutorial is located within the download bundle under `envers/`.
****
[[hibernate-gsg-tutorial-envers-config]]
=== persistence.xml
This file was discussed in the Jakarta Persistence tutorial in <<hibernate-gsg-tutorial-jpa-config>>, and is essentially the same here.
This file is unchanged from <<hibernate-gsg-tutorial-jpa-config,what we had before>>.
[[hibernate-gsg-tutorial-envers-entity]]
=== The annotated entity Java class
Again, the entity is largely the same as in <<hibernate-gsg-tutorial-jpa-entity>>. The major difference is the
addition of the `@org.hibernate.envers.Audited` annotation, which tells Envers to automatically track changes to this
entity.
The entity class is also almost identical to what we had <<hibernate-gsg-tutorial-annotations-entity,previously>>.
The major difference is the addition of the annotation `@org.hibernate.envers.Audited`, which tells Envers to automatically track changes to this entity.
[[hibernate-gsg-tutorial-envers-test]]
=== Example code
@ -32,28 +30,23 @@ initial revision as well as the updated revision. A revision refers to a histor
[[hibernate-gsg-tutorial-envers-test-api]]
.Using the `org.hibernate.envers.AuditReader`
====
[source, JAVA]
[source, java]
----
public void testBasicUsage() {
...
AuditReader reader = AuditReaderFactory.get( entityManager );
Event firstRevision = reader.find( Event.class, 2L, 1 );
AuditReader reader = AuditReaderFactory.get( entityManager ); <1>
Event firstRevision = reader.find( Event.class, 2L, 1 ); <2>
...
Event secondRevision = reader.find( Event.class, 2L, 2 );
Event secondRevision = reader.find( Event.class, 2L, 2 ); <3>
...
}
----
====
We see that an `org.hibernate.envers.AuditReader` is obtained from the `org.hibernate.envers.AuditReaderFactory`
which wraps the `jakarta.persistence.EntityManager`.
Next, the `find` method retrieves specific revisions of the entity. The first call says to find revision number
1 of Event with id 2. The second call says to find revision number 2 of Event with id 2.
<1> An `org.hibernate.envers.AuditReader` is obtained from the `org.hibernate.envers.AuditReaderFactory` which wraps the JPA `EntityManager`.
<2> The `find` method retrieves specific revisions of the entity. The first call retrieves revision number 1 of the `Event` with id 2.
<3> Later, the second call asks for revision number 2 of the `Event` with id 2.
[[hibernate-gsg-tutorial-annotations-further]]
[[hibernate-gsg-tutorial-envers-further]]
=== Take it further!
.Practice Exercises

View File

@ -1,118 +1,124 @@
[[tutorial_jpa]]
== Tutorial Using the Java Persistence API (Jakarta Persistence)
NOTE: This tutorial is located within the download bundle under `entitymanager/`.
== Tutorial using JPA-standard APIs
.Objectives
- [*] Configure Hibernate using `peristence.xml`
- [*] Bootstrap a Jakarta Persistence `EntityManagerFactory`
- [*] Use annotations to provide mapping information
- [*] Use Jakarta Persistence API calls
- [*] Use `EntityManager` to persist and query data
****
This tutorial is located within the download bundle under `entitymanager/`.
****
[[hibernate-gsg-tutorial-jpa-config]]
=== persistence.xml
The previous tutorials used the Hibernate-specific `hibernate.cfg.xml` configuration file. Jakarta Persistence, however, defines
a different bootstrap process that uses its own configuration file named `persistence.xml`. This bootstrapping process
is defined by the Jakarta Persistence specification. In Java(TM) SE environments the persistence provider (Hibernate in this case)
is required to locate all Jakarta Persistence configuration files by classpath lookup of the `META-INF/persistence.xml` resource name.
JPA defines a different bootstrap process, along with a standard configuration file format named `persistence.xml`.
In Java(TM) SE environments the persistence provider (Hibernate) is required to locate every JPA configuration file in the classpath at the path `META-INF/persistence.xml`.
[[hibernate-gsg-tutorial-jpa-config-pu]]
.persistence.xml
====
[source, XML]
.Configuration via `persistence.xml`
[source, 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">
...
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"> <1>
<description>
Persistence unit for the Jakarta Persistence tutorial of the Hibernate Getting Started Guide
</description>
<class>org.hibernate.tutorial.em.Event</class> <2>
<properties> <3>
<!-- Database connection settings -->
<property name="jakarta.persistence.jdbc.url" value="jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1" />
<property name="jakarta.persistence.jdbc.user" value="sa" />
<property name="jakarta.persistence.jdbc.password" value="" />
<!-- Automatically export the schema -->
<property name="jakarta.persistence.schema-generation.database.action" value="create" />
<!-- Echo all executed SQL to console -->
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="true" />
<property name="hibernate.highlight_sql" value="true" />
</properties>
</persistence-unit>
</persistence>
----
====
<1> A `persistence.xml` file should provide a unique name for each _persistence unit_ it declares.
Applications use this name to reference the configuration when obtaining an `EntityManagerFactory`.
<2> The `<class/>` element registers our annotated entity class.
<3> The settings specified as `<properties/>` elements were already discussed in <<hibernate-gsg-tutorial-annotations-config>>.
Here JPA-standard property names are used where possible.
`persistence.xml` files should provide a unique name for each "persistence unit". Applications use this name to
reference the configuration when obtaining an `jakarta.persistence.EntityManagerFactory` reference.
The settings defined in the `<properties/>` element are discussed in <<hibernate-gsg-tutorial-basic-config>>.
Here the `jakarta.persistence`-prefixed varieties are used when possible. Notice that the remaining
Hibernate-specific configuration setting names are now prefixed with `hibernate.`.
NOTE:: Configuration properties prefixed with the legacy Java EE "namespace" (`javax.persistence.*`) are also still
supported, although the Jakarta EE version (`jakarta.persistence.*`) should be preferred
Additionally, the `<class/>` element functions the same as we saw in <<hibernate-gsg-tutorial-annotations-config>>.
[NOTE]
Configuration properties prefixed with the legacy Java EE namespace `javax.persistence` are still
recognized, but the Jakarta EE namespace `jakarta.persistence` is now preferred.
[[hibernate-gsg-tutorial-jpa-entity]]
=== The annotated entity Java class
The entity is exactly the same as in <<hibernate-gsg-tutorial-annotations-entity>>.
The entity class is exactly the same as in <<hibernate-gsg-tutorial-annotations-entity>>.
[[hibernate-gsg-tutorial-jpa-test]]
=== Example code
The previous tutorials used the Hibernate native APIs. This tutorial uses the Jakarta Persistence APIs.
The previous tutorials used Hibernate native APIs.
This tutorial uses the standard Jakarta Persistence APIs.
[[hibernate-gsg-tutorial-jpa-test-setUp]]
.Obtaining the jakarta.persistence.EntityManagerFactory
====
[source, JAVA]
[source, java]
----
protected void setUp() throws Exception {
sessionFactory = Persistence.createEntityManagerFactory( "org.hibernate.tutorial.jpa" );
protected void setUp() {
sessionFactory = Persistence.createEntityManagerFactory("org.hibernate.tutorial.jpa"); <1>
}
----
====
Notice again that the persistence unit name is `org.hibernate.tutorial.jpa`, which matches <<hibernate-gsg-tutorial-jpa-config-pu>>.
<1> Notice again that the persistence unit name is `org.hibernate.tutorial.jpa`, which matches <<hibernate-gsg-tutorial-jpa-config-pu>>.
[[hibernate-gsg-tutorial-jpa-test-saving]]
.Saving (persisting) entities
====
[source, JAVA]
The code to persist and query entities is almost identical to <<hibernate-gsg-tutorial-basic-test-saving>>.
Unfortunately, `EntityManagerFactory` doesn't have a nice `inTransaction()` method like `SessionFactory` does, so we had to write our own:
.Managing transactions in JPA
[source, java]
----
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();
----
====
The code is similar to <<hibernate-gsg-tutorial-basic-test-saving>>. The `jakarta.persistence.EntityManager` interface
is used instead of the `org.hibernate.Session` interface. Jakarta Persistence calls this operation "persist" instead of "save".
[[hibernate-gsg-tutorial-jpa-test-list]]
.Obtaining a list of entities
====
[source, JAVA]
----
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() );
void inTransaction(Consumer<EntityManager> work) {
EntityManager entityManager = entityManagerFactory.createEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
try {
transaction.begin();
work.accept(entityManager);
transaction.commit();
}
catch (Exception e) {
if (transaction.isActive()) {
transaction.rollback();
}
throw e;
}
finally {
entityManager.close();
}
}
entityManager.getTransaction().commit();
entityManager.close();
----
====
Again, the code is pretty similar to what we saw in <<hibernate-gsg-tutorial-basic-test-list>>.
[TIP]
If you use JPA in Java SE, you'll need to copy/paste this function into your project.
[[hibernate-gsg-tutorial-annotations-further]]
[[hibernate-gsg-tutorial-jpa-further]]
=== Take it further!
.Practice Exercises
- [ ] Develop an EJB Session bean to investigate implications of using a container-managed
persistence context. Try both stateless and stateful use-cases.
- [ ] Use listeners with CDI-based injection to develop a JMS-based event message hub
- [ ] Learn how to use CDI to inject a container-managed `EntityManager` in Quarkus.
See https://quarkus.io/guides/hibernate-orm[the Quarkus website] for instructions.

View File

@ -1,231 +0,0 @@
[[tutorial-native]]
== Tutorial Using Native Hibernate APIs and hbm.xml Mapping
NOTE: This tutorial is located within the download bundle under `basic/`.
.Objectives
- [*] Bootstrap a Hibernate `SessionFactory`
- [*] Use Hibernate mapping (`hbm.xml`) files to provide mapping information
- [*] Use the Hibernate native APIs
[[hibernate-gsg-tutorial-basic-config]]
=== The Hibernate configuration file
For this tutorial, the `hibernate.cfg.xml` file defines the Hibernate configuration information.
The `connection.driver_class`, `connection.url`, `connection.username` and `connection.password` `<property/>` elements
define JDBC connection information. These tutorials utilize the H2 in-memory database, so the values of these properties
are all specific to running H2 in its in-memory mode. `connection.pool_size` is used to configure the number of
connections in Hibernate's built-in connection pool.
IMPORTANT: The built-in Hibernate connection pool is in no way intended for production use. It lacks several
features found on production-ready connection pools.
The `dialect` property specifies the particular SQL variant with which Hibernate will converse.
TIP: In most cases, Hibernate is able to properly determine which dialect to use. This is particularly useful
if your application targets multiple databases.
The `hbm2ddl.auto` property enables automatic generation of database schemas directly into the database.
Finally, add the mapping file(s) for persistent classes to the configuration. The `resource` attribute of the
`<mapping/>` element causes Hibernate to attempt to locate that mapping as a classpath resource using a
`java.lang.ClassLoader` lookup.
There are many ways and options to bootstrap a Hibernate `SessionFactory`. For additional details, see
the _Native Bootstrapping_ topical guide.
[[hibernate-gsg-tutorial-basic-entity]]
=== The entity Java class
The entity class for this tutorial is `org.hibernate.tutorial.hbm.Event`
.Notes About the Entity
* This class uses standard JavaBean naming conventions for property getter and setter methods, as well as
private visibility for the fields. Although this is the recommended design, it is not required.
* The no-argument constructor, which is also a JavaBean convention, is a requirement for all persistent classes.
Hibernate needs to create objects for you, using Java Reflection. The constructor can be private. However, package
or public visibility is required for runtime proxy generation and efficient data retrieval without bytecode
instrumentation.
[[hibernate-gsg-tutorial-basic-mapping]]
=== The mapping file
The mapping file for this tutorial is the classpath resource `org/hibernate/tutorial/hbm/Event.hbm.xml` (as discussed above).
Hibernate uses the mapping metadata to determine how to load and store objects of the persistent class. The Hibernate
mapping file is one choice for providing Hibernate with this metadata.
[[hibernate-gsg-tutorial-basic-mapping-class]]
.The class mapping element
====
[source, XML]
----
<class name="Event" table="EVENTS">
...
</class>
----
====
.Functions of the <varname>class</varname> mapping element
* The `name` attribute (combined here with the `package` attribute from the containing `<hibernate-mapping/>` element)
names the FQN of the class to be defined as an entity.
* The `table` attribute names the database table which contains the data for this entity.
Instances of the `Event` class are now mapped to rows in the `EVENTS` database table.
[[hibernate-gsg-tutorial-basic-mapping-id]]
.The id mapping element
====
[source, XML]
----
<id name="id" column="EVENT_ID">
...
</id>
----
====
Hibernate uses the property named by the `<id/>` element to uniquely identify rows in the table.
IMPORTANT: It is not required for the id element to map to the table's actual primary key column(s), but it is
the normal convention. Tables mapped in Hibernate do not even need to define primary keys. However, it is strongly
recommend that all schemas define proper referential integrity. Therefore id and primary key are used interchangeably
throughout Hibernate documentation.
The `<id/>` element here names the EVENT_ID column as the primary key of the EVENTS table. It also identifies the
`id` property of the `Event` class as the property containing the identifier value.
The `generator` element informs Hibernate about which strategy is used to generated primary key values for this entity.
This example uses a simple incrementing count.
[[hibernate-gsg-tutorial-basic-mapping-property]]
.The property mapping element
====
[source, XML]
----
<property name="date" type="timestamp" column="EVENT_DATE"/>
<property name="title"/>
----
====
The two `<property/>` elements declare the remaining two persistent properties of the `Event` class: `date` and `title`.
The `date` property mapping includes the `column` attribute, but the `title` does not.
In the absence of a `column` attribute, Hibernate uses the property name as the column name.
This is appropriate for `title`, but since `date` is a reserved keyword in most databases, you need to specify a
non-reserved word for the column name.
The `title` mapping also lacks a type attribute. The types declared and used in the mapping files are neither Java data
types nor SQL database types. Instead, they are *Hibernate mapping types*, which are converters which translate between
Java and SQL data types. Hibernate attempts to determine the correct conversion and mapping type autonomously if the
type attribute is not specified in the mapping, by using Java reflection to determine the Java type of the declared
property and using a default mapping type for that Java type.
In some cases this automatic detection might not choose the default you expect or need, as seen with the
`date` property. Hibernate cannot know if the property, which is of type `java.util.Date`, should map to an SQL
_DATE_, _TIME_, or _TIMESTAMP_ datatype. Full date and time information is preserved by mapping the property to
the _timestamp_ converter, which identifies the converter as declared by `org.hibernate.type.StandardBasicTypes.TIMESTAMP`.
TIP: Hibernate determines the mapping type using reflection when the mapping files are processed. This process adds
overhead in terms of time and resources. If startup performance is important, consider explicitly defining the type
to use.
[[hibernate-gsg-tutorial-basic-test]]
=== Example code
The `org.hibernate.tutorial.hbm.NativeApiIllustrationTest` class illustrates using the Hibernate native API.
NOTE: The examples in these tutorials are presented as JUnit tests, for ease of use. One benefit of this
approach is that `setUp` and `tearDown` roughly illustrate how a `org.hibernate.SessionFactory` is created at the
start-up of an application and closed at the end of the application lifecycle.
[[hibernate-gsg-tutorial-basic-test-setUp]]
.Obtaining the `org.hibernate.SessionFactory`
====
[source, JAVA]
----
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 );
}
}
----
====
The `setUp` method first builds a `org.hibernate.boot.registry.StandardServiceRegistry` instance which incorporates
configuration information into a working set of Services for use by the SessionFactory. In this tutorial
we defined all configuration information in `hibernate.cfg.xml` so there is not much interesting to see here.
Using the `StandardServiceRegistry` we create the `org.hibernate.boot.MetadataSources` which is the start point for
telling Hibernate about your domain model. Again, since we defined that in `hibernate.cfg.xml` so there is not much
interesting to see here.
`org.hibernate.boot.Metadata` represents the complete, partially validated view of the application domain model which the
`SessionFactory` will be based on.
The final step in the bootstrap process is to build the `SessionFactory`. The `SessionFactory` is a
thread-safe object that is instantiated once to serve the entire application.
The `SessionFactory` acts as a factory for `org.hibernate.Session` instances, which should be thought of
as a corollary to a "unit of work".
[[hibernate-gsg-tutorial-basic-test-saving]]
.Saving entities
====
[source, JAVA]
----
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()` first creates some new `Event` objects and hands them over to Hibernate for management, using the
`save()` method. Hibernate now takes responsibility to perform an _INSERT_ on the database for each `Event`.
[[hibernate-gsg-tutorial-basic-test-list]]
.Obtaining a list of entities
====
[source, JAVA]
----
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();
----
====
Here we see an example of the Hibernate Query Language (HQL) to load all existing `Event` objects from the database
by generating the appropriate _SELECT_ SQL, sending it to the database and populating `Event` objects with the result
set data.
[[hibernate-gsg-tutorial-annotations-further]]
=== Take it further!
.Practice Exercises
- [ ] Reconfigure the examples to connect to your own persistent relational database.
- [ ] Add an association to the `Event` entity to model a message thread.

View File

@ -1,89 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.tutorial.annotations;
import java.util.Date;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import junit.framework.TestCase;
/**
* Illustrates the use of Hibernate native APIs. The code here is unchanged from the {@code basic} example, the
* only difference being the use of annotations to supply the metadata instead of Hibernate mapping files.
*
* @author Steve Ebersole
*/
public class AnnotationsIllustrationTest extends TestCase {
private SessionFactory sessionFactory;
@Override
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 );
}
}
@Override
protected void tearDown() throws Exception {
if ( sessionFactory != null ) {
sessionFactory.close();
}
}
@SuppressWarnings("unchecked")
public void testBasicUsage() {
// create a couple of events...
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();
// now lets pull events from the database and list them
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();
}
}

View File

@ -23,38 +23,36 @@
*/
package org.hibernate.tutorial.annotations;
import java.util.Date;
import java.time.LocalDateTime;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import jakarta.persistence.Temporal;
import jakarta.persistence.TemporalType;
import org.hibernate.annotations.GenericGenerator;
@Entity
@Table( name = "EVENTS" )
@Table(name = "Events")
public class Event {
@Id
@GeneratedValue
private Long id;
private String title;
private Date date;
@Column(name = "eventDate")
private LocalDateTime date;
public Event() {
// this form used by Hibernate
}
public Event(String title, Date date) {
public Event(String title, LocalDateTime date) {
// for application use, to create new events
this.title = title;
this.date = date;
}
@Id
@GeneratedValue(generator="increment")
@GenericGenerator(name="increment", strategy = "increment")
public Long getId() {
return id;
}
@ -63,13 +61,11 @@ public class Event {
this.id = id;
}
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "EVENT_DATE")
public Date getDate() {
public LocalDateTime getDate() {
return date;
}
public void setDate(Date date) {
public void setDate(LocalDateTime date) {
this.date = date;
}

View File

@ -21,10 +21,9 @@
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.tutorial.hbm;
package org.hibernate.tutorial.annotations;
import java.util.Date;
import java.util.List;
import java.time.LocalDateTime;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
@ -34,55 +33,57 @@ import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import junit.framework.TestCase;
import static java.lang.System.out;
import static java.time.LocalDateTime.now;
/**
* Illustrates use of Hibernate native APIs.
* Illustrates the use of Hibernate native APIs, including the use
* of org.hibernate.boot for configuration and bootstrap.
* Configuration properties are sourced from hibernate.properties.
*
* @author Steve Ebersole
*/
public class NativeApiIllustrationTest extends TestCase {
public class HibernateIllustrationTest extends TestCase {
private SessionFactory sessionFactory;
@Override
protected void setUp() throws Exception {
protected void setUp() {
// A SessionFactory is set up once for an application!
final StandardServiceRegistry registry = new StandardServiceRegistryBuilder()
.configure() // configures settings from hibernate.cfg.xml
.build();
final StandardServiceRegistry registry =
new StandardServiceRegistryBuilder()
.build();
try {
sessionFactory = new MetadataSources( registry ).buildMetadata().buildSessionFactory();
sessionFactory =
new MetadataSources(registry)
.addAnnotatedClass(Event.class)
.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 );
// The registry would be destroyed by the SessionFactory, but we
// had trouble building the SessionFactory so destroy it manually.
StandardServiceRegistryBuilder.destroy(registry);
}
}
@Override
protected void tearDown() throws Exception {
protected void tearDown() {
if ( sessionFactory != null ) {
sessionFactory.close();
}
}
@SuppressWarnings("unchecked")
public void testBasicUsage() {
// create a couple of events...
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();
sessionFactory.inTransaction(session -> {
session.persist(new Event("Our very first event!", now()));
session.persist(new Event("A follow up event", now()));
});
// now lets pull events from the database and list them
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();
sessionFactory.inTransaction(session -> {
session.createSelectionQuery("from Event", Event.class).getResultList()
.forEach(event -> out.println("Event (" + event.getDate() + ") : " + event.getTitle()));
});
}
}

View File

@ -1,42 +0,0 @@
<?xml version='1.0' encoding='utf-8'?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
-->
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- Database connection settings -->
<property name="connection.driver_class">org.h2.Driver</property>
<property name="connection.url">jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1</property>
<property name="connection.username">sa</property>
<property name="connection.password"></property>
<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">1</property>
<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.H2Dialect</property>
<!-- Disable the second-level cache -->
<property name="cache.provider_class">org.hibernate.cache.internal.NoCacheProvider</property>
<!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property>
<!-- Drop and re-create the database schema on startup -->
<property name="hbm2ddl.auto">create</property>
<!-- Names the annotated entity class -->
<mapping class="org.hibernate.tutorial.annotations.Event"/>
</session-factory>
</hibernate-configuration>

View File

@ -0,0 +1,12 @@
# Database connection settings
hibernate.connection.url=jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1
hibernate.connection.username=sa
hibernate.connection.password=
# Echo all executed SQL to console
hibernate.show_sql=true
hibernate.format_sql=true
hibernate.highlight_sql=true
# Automatically export the schema
hibernate.hbm2ddl.auto=create

View File

@ -1,28 +0,0 @@
<?xml version="1.0"?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.hibernate.tutorials</groupId>
<artifactId>hibernate-tutorials</artifactId>
<version>$version</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>hibernate-tutorial-hbm</artifactId>
<name>Hibernate hbm.xml Tutorial</name>
<description>Hibernate tutorial illustrating the use of native APIs and hbm.xml for mapping metadata</description>
<properties>
<!-- Skip artifact deployment -->
<maven.deploy.skip>true</maven.deploy.skip>
</properties>
</project>

View File

@ -1,23 +0,0 @@
<?xml version="1.0"?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
-->
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.hibernate.tutorial.hbm">
<class name="Event" table="EVENTS">
<id name="id" column="EVENT_ID">
<generator class="increment"/>
</id>
<property name="date" type="timestamp" column="EVENT_DATE"/>
<property name="title"/>
</class>
</hibernate-mapping>

View File

@ -1,67 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.tutorial.hbm;
import java.util.Date;
public class Event {
private Long id;
private String title;
private Date date;
public Event() {
// this form used by Hibernate
}
public Event(String title, Date date) {
// for application use, to create new events
this.title = title;
this.date = date;
}
public Long getId() {
return id;
}
private void setId(Long id) {
this.id = id;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}

View File

@ -1,41 +0,0 @@
<?xml version='1.0' encoding='utf-8'?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
-->
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- Database connection settings -->
<property name="connection.driver_class">org.h2.Driver</property>
<property name="connection.url">jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1</property>
<property name="connection.username">sa</property>
<property name="connection.password"/>
<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">1</property>
<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.H2Dialect</property>
<!-- Disable the second-level cache -->
<property name="cache.provider_class">org.hibernate.cache.internal.NoCacheProvider</property>
<!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property>
<!-- Drop and re-create the database schema on startup -->
<property name="hbm2ddl.auto">create</property>
<mapping resource="org/hibernate/tutorial/hbm/Event.hbm.xml"/>
</session-factory>
</hibernate-configuration>

View File

@ -23,61 +23,57 @@
*/
package org.hibernate.tutorial.em;
import java.util.Date;
import java.time.LocalDateTime;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import jakarta.persistence.Temporal;
import jakarta.persistence.TemporalType;
import org.hibernate.annotations.GenericGenerator;
@Entity
@Table( name = "EVENTS" )
@Table(name = "Events")
public class Event {
private Long id;
private String title;
private Date date;
@Id
@GeneratedValue
private Long id;
private String title;
@Column(name = "eventDate")
private LocalDateTime date;
public Event() {
// this form used by Hibernate
}
public Event(String title, Date date) {
public Event(String title, LocalDateTime date) {
// for application use, to create new events
this.title = title;
this.date = date;
}
@Id
@GeneratedValue(generator="increment")
@GenericGenerator(name="increment", strategy = "increment")
public Long getId() {
public Long getId() {
return id;
}
}
private void setId(Long id) {
private void setId(Long id) {
this.id = id;
}
}
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "EVENT_DATE")
public Date getDate() {
public LocalDateTime getDate() {
return date;
}
}
public void setDate(Date date) {
public void setDate(LocalDateTime date) {
this.date = date;
}
}
public String getTitle() {
public String getTitle() {
return title;
}
}
public void setTitle(String title) {
public void setTitle(String title) {
this.title = title;
}
}
}

View File

@ -23,51 +23,73 @@
*/
package org.hibernate.tutorial.em;
import java.util.Date;
import java.util.List;
import java.util.function.Consumer;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Persistence;
import jakarta.persistence.EntityTransaction;
import junit.framework.TestCase;
import static java.lang.System.out;
import static java.time.LocalDateTime.now;
import static jakarta.persistence.Persistence.createEntityManagerFactory;
/**
* Illustrates basic use of Hibernate as a Jakarta Persistence provider.
* Configuration properties are sourced from persistence.xml.
*
* @author Steve Ebersole
*/
public class EntityManagerIllustrationTest extends TestCase {
public class JPAIllustrationTest extends TestCase {
private EntityManagerFactory entityManagerFactory;
@Override
protected void setUp() throws Exception {
// like discussed with regards to SessionFactory, an EntityManagerFactory is set up once for an application
// IMPORTANT: notice how the name here matches the name we gave the persistence-unit in persistence.xml!
entityManagerFactory = Persistence.createEntityManagerFactory( "org.hibernate.tutorial.jpa" );
protected void setUp() {
// an EntityManagerFactory is set up once for an application
// IMPORTANT: notice how the name here matches the name we
// gave the persistence-unit in persistence.xml
entityManagerFactory = createEntityManagerFactory("org.hibernate.tutorial.jpa");
}
@Override
protected void tearDown() throws Exception {
protected void tearDown() {
entityManagerFactory.close();
}
public void testBasicUsage() {
// create a couple of events...
EntityManager entityManager = entityManagerFactory.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();
inTransaction(entityManager -> {
entityManager.persist(new Event("Our very first event!", now()));
entityManager.persist(new Event("A follow up event", now()));
});
// now lets pull events from the database and list them
entityManager = entityManagerFactory.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();
inTransaction(entityManager -> {
entityManager.createQuery("select e from Event e", Event.class).getResultList()
.forEach(event -> out.println("Event (" + event.getDate() + ") : " + event.getTitle()));
});
}
void inTransaction(Consumer<EntityManager> work) {
EntityManager entityManager = entityManagerFactory.createEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
try {
transaction.begin();
work.accept(entityManager);
transaction.commit();
}
catch (Exception e) {
if (transaction.isActive()) {
transaction.rollback();
}
throw e;
}
finally {
entityManager.close();
}
}
}

View File

@ -17,13 +17,18 @@
<class>org.hibernate.tutorial.em.Event</class>
<properties>
<property name="jakarta.persistence.jdbc.driver" value="org.h2.Driver" />
<!-- Database connection settings -->
<property name="jakarta.persistence.jdbc.url" value="jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1" />
<property name="jakarta.persistence.jdbc.user" value="sa" />
<property name="jakarta.persistence.jdbc.password" value="" />
<!-- Automatically export the schema -->
<property name="jakarta.persistence.schema-generation.database.action" value="create" />
<!-- Echo all executed SQL to console -->
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.hbm2ddl.auto" value="create" />
<property name="hibernate.format_sql" value="true" />
<property name="hibernate.highlight_sql" value="true" />
</properties>
</persistence-unit>

View File

@ -27,18 +27,22 @@ import java.util.Date;
import java.util.List;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Persistence;
import junit.framework.TestCase;
import org.hibernate.envers.AuditReader;
import org.hibernate.envers.AuditReaderFactory;
import static java.time.LocalDateTime.now;
import static jakarta.persistence.Persistence.createEntityManagerFactory;
/**
* Illustrates the set up and use of Envers.
* Illustrates the setup and use of Envers.
* <p>
* This example is different from the others in that we really need to save multiple revisions to the entity in
* order to get a good look at Envers in action.
* This example is different from the others because we need to have
* multiple revisions to the entity in order to get a good look at
* Envers in action.
*
* @author Steve Ebersole
*/
@ -46,14 +50,12 @@ public class EnversIllustrationTest extends TestCase {
private EntityManagerFactory entityManagerFactory;
@Override
protected void setUp() throws Exception {
// like discussed with regards to SessionFactory, an EntityManagerFactory is set up once for an application
// IMPORTANT: notice how the name here matches the name we gave the persistence-unit in persistence.xml!
entityManagerFactory = Persistence.createEntityManagerFactory( "org.hibernate.tutorial.envers" );
protected void setUp() {
entityManagerFactory = createEntityManagerFactory( "org.hibernate.tutorial.envers" );
}
@Override
protected void tearDown() throws Exception {
protected void tearDown() {
entityManagerFactory.close();
}
@ -61,8 +63,8 @@ public class EnversIllustrationTest extends TestCase {
// create a couple of events
EntityManager entityManager = entityManagerFactory.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.persist( new Event( "Our very first event!", now() ) );
entityManager.persist( new Event( "A follow up event", now() ) );
entityManager.getTransaction().commit();
entityManager.close();
@ -82,7 +84,7 @@ public class EnversIllustrationTest extends TestCase {
entityManager = entityManagerFactory.createEntityManager();
entityManager.getTransaction().begin();
Event myEvent = entityManager.find( Event.class, 2L ); // we are using the increment generator, so we know 2 is a valid id
myEvent.setDate( new Date() );
myEvent.setDate( now() );
myEvent.setTitle( myEvent.getTitle() + " (rescheduled)" );
entityManager.getTransaction().commit();
entityManager.close();

View File

@ -23,70 +23,60 @@
*/
package org.hibernate.tutorial.envers;
import java.util.Date;
import java.time.LocalDateTime;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import jakarta.persistence.Temporal;
import jakarta.persistence.TemporalType;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.envers.Audited;
@Entity
@Table( name = "EVENTS" )
@Audited // <--- this tell Envers to audit (track changes to) this entity
@Table(name = "Events")
@Audited // <--- this tells Envers to audit (track changes to) this entity
public class Event {
private Long id;
private String title;
private Date date;
@Id
@GeneratedValue
private Long id;
private String title;
@Column(name = "eventDate")
private LocalDateTime date;
public Event() {
// this form used by Hibernate
}
public Event(String title, Date date) {
public Event(String title, LocalDateTime date) {
// for application use, to create new events
this.title = title;
this.date = date;
}
@Id
@GeneratedValue(generator="increment")
@GenericGenerator(name="increment", strategy = "increment")
public Long getId() {
public Long getId() {
return id;
}
}
private void setId(Long id) {
private void setId(Long id) {
this.id = id;
}
}
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "EVENT_DATE")
public Date getDate() {
public LocalDateTime getDate() {
return date;
}
}
public void setDate(Date date) {
public void setDate(LocalDateTime date) {
this.date = date;
}
}
public String getTitle() {
public String getTitle() {
return title;
}
}
public void setTitle(String title) {
public void setTitle(String title) {
this.title = title;
}
@Override
public int hashCode() {
int result = title.hashCode();
result = 31 * result + date.hashCode();
return result;
}
}

View File

@ -17,13 +17,18 @@
<class>org.hibernate.tutorial.envers.Event</class>
<properties>
<property name="jakarta.persistence.jdbc.driver" value="org.h2.Driver" />
<!-- Database connection settings -->
<property name="jakarta.persistence.jdbc.url" value="jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1" />
<property name="jakarta.persistence.jdbc.user" value="sa" />
<property name="jakarta.persistence.jdbc.password" value="" />
<!-- Automatically export the schema -->
<property name="jakarta.persistence.schema-generation.database.action" value="create" />
<!-- Echo all executed SQL to console -->
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.hbm2ddl.auto" value="create" />
<property name="hibernate.format_sql" value="true" />
<property name="hibernate.highlight_sql" value="true" />
</properties>
</persistence-unit>

View File

@ -349,8 +349,8 @@ span.icon>.fa{cursor:default}
.admonitionblock td.icon .icon-warning:before{content:"\f071";color:#bf6900}
.admonitionblock td.icon .icon-caution:before{content:"\f06d";color:#bf3400}
.admonitionblock td.icon .icon-important:before{content:"\f06a";color:#bf0000}
.conum[data-value]{display:inline-block;color:#fff!important;background-color:rgba(0,0,0,.8);-webkit-border-radius:100px;border-radius:100px;text-align:center;font-size:.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:"Open Sans","DejaVu Sans",sans-serif;font-style:normal;font-weight:bold}
.conum[data-value] *{color:#fff!important}
.conum[data-value]{display:inline-block;color:black!important;background-color:white;-webkit-border-radius:100px;border-radius:100px;text-align:center;font-size:.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:"Open Sans","DejaVu Sans",sans-serif;font-style:normal;font-weight:bold}
.conum[data-value] *{color:black!important}
.conum[data-value]+b{display:none}
.conum[data-value]:after{content:attr(data-value)}
pre .conum[data-value]{position:relative;top:-.125em}

View File

@ -52,11 +52,6 @@ import static java.util.Comparator.comparingInt;
*/
public class QueryEngineImpl implements QueryEngine {
/**
* The default soft reference count.
*/
public static final int DEFAULT_QUERY_PLAN_MAX_COUNT = 2048;
private static final Logger LOG_HQL_FUNCTIONS = CoreLogging.logger("org.hibernate.HQL_FUNCTIONS");
public static QueryEngine from(SessionFactoryImplementor sessionFactory, MetadataImplementor metadata) {
@ -205,7 +200,7 @@ public class QueryEngineImpl implements QueryEngine {
if ( explicitUseCache || explicitMaxPlanSize != null && explicitMaxPlanSize > 0 ) {
final int size = explicitMaxPlanSize != null
? explicitMaxPlanSize
: DEFAULT_QUERY_PLAN_MAX_COUNT;
: QueryEngine.DEFAULT_QUERY_PLAN_MAX_COUNT;
return new QueryInterpretationCacheStandardImpl( size, statisticsSupplier );
}

View File

@ -25,6 +25,11 @@ import org.hibernate.type.spi.TypeConfiguration;
@Incubating
public interface QueryEngine {
/**
* The default soft reference count.
*/
int DEFAULT_QUERY_PLAN_MAX_COUNT = 2048;
NativeQueryInterpreter getNativeQueryInterpreter();
QueryInterpretationCache getInterpretationCache();