Hibernate is an open-source Java object/relational mapping (ORM) service. It uses mapping metadata to connect Java classes and properties to SQL tables and columns, handling much of the work of storing objects and reconstructing them from database rows. It implements the Jakarta Persistence API (JPA), which defines what a persistence provider must do; Hibernate supplies the implementation. section 1.3 section 2.1
Choose the API according to the job. Standard JPA uses `EntityManagerFactory` and `EntityManager` and allows a different provider. Native Hibernate uses `SessionFactory` and `Session`, exposing features beyond JPA but depending directly on Hibernate. Spring Data JPA adds a repository layer above a JPA provider such as Hibernate. Most applications do not need native bootstrap configuration. section 2.4 section 2.8
Store and change a message
Create an `EntityManager`, begin a transaction, construct a `Message`, and call `persist(message)` before committing. A JPQL query names the persistent `Message` class, not its table. Change the text of a managed message inside a transaction, and Hibernate detects the change and issues the database update without an explicit update call. section 2.3.3
Listing 2.6 The HelloWorldHibernateTest class
Path: Ch02/helloworld/src/test/java/com/manning/javapersistence/ch02 /HelloWorldHibernateTest.java public class HelloWorldHibernateTest { private static SessionFactory createSessionFactory() { Configuration configuration = new Configuration(); #1 configuration.configure().addAnnotatedClass(Message.class); #2 ServiceRegistry serviceRegistry = new #3 StandardServiceRegistryBuilder(). #3 applySettings(configuration.getProperties()).build(); #3 return configuration.buildSessionFactory(serviceRegistry); #4 } @Test public void storeLoadMessage() { try (SessionFactory sessionFactory = createSessionFactory(); #5 Session session = sessionFactory.openSession()) { #6 session.beginTransaction(); #7 Message message = new Message(); #8 message.setText("Hello World from Hibernate!"); #8 session.persist(message); #9 session.getTransaction().commit(); #10 // INSERT into MESSAGE (ID, TEXT) // values (1, 'Hello World from Hibernate!') session.beginTransaction(); #11 CriteriaQuery<Message> criteriaQuery = #12 session.getCriteriaBuilder().createQuery(Message.class); #12 criteriaQuery.from(Message.class); #13 List<Message> messages = #14 session.createQuery(criteriaQuery).getResultList(); #14 // SELECT * from MESSAGE session.getTransaction().commit(); #15 assertAll( #16 () -> assertEquals(1, messages.size()), #16 () -> assertEquals("Hello World from Hibernate!", #17 messages.get(0).getText()) #17 ); } } } #1 To create a <kbd>SessionFactory</kbd>, we first need to create a configuration. #2 We need to call the <kbd>configure</kbd> method on it and to add <kbd>Message</kbd> to it as an annotated class. The execution of the <kbd>configure</kbd> method will load the content of the default hibernate.cfg.xml file. #3 The builder pattern helps us create the immutable service registry and configure it by applying settings with chained method calls. A <kbd>ServiceRegistry</kbd> hosts and manages services that need access to the <kbd>SessionFactory</kbd>. Services are classes that provide pluggable implementations of different types of functionality to Hibernate. #4 Build a <kbd>SessionFactory</kbd> using the configuration and the service registry we have previously created. #5 The <kbd>SessionFactory</kbd> created with the <kbd>createSessionFactory</kbd> method we previously defined is passed as an argument to a <kbd>try</kbd> with resources, as <kbd>SessionFactory</kbd> implements the <kbd>AutoCloseable</kbd> interface. #6 Similarly, we begin a new session with the database by creating a <kbd>Session</kbd>, which also implements the <kbd>AutoCloseable</kbd> interface. This is our context for all persistence operations. #6 Get access to the standard transaction API and begin a transaction on this thread of execution. #8 Create a new instance of the mapped domain model class <kbd>Message</kbd>, and set its <kbd>text</kbd> property. #9 Enlist the transient instance with the persistence context; we make it persistent. Hibernate now knows that we wish to store that data, but it doesn't necessarily call the database immediately. The native Hibernate API is pretty similar to the standard JPA, and most methods have the same name. #10 Synchronize the session with the database, and close the current session on commit of the transaction automatically. #11 Begin another transaction. Every interaction with the database should occur within transaction boundaries, even if we’re only reading data. #12 Create an instance of <kbd>CriteriaQuery</kbd> by calling the <kbd>CriteriaBuilder</kbd> <kbd>createQuery()</kbd> method. A <kbd>CriteriaBuilder</kbd> is used to construct criteria queries, compound selections, expressions, predicates, and orderings. A <kbd>CriteriaQuery</kbd> defines functionality that is specific to top-level queries. <kbd>CriteriaBuilder</kbd> and <kbd>CriteriaQuery</kbd> belong to the Criteria API, which allows us to build a query programmatically. #13 Create and add a query root corresponding to the given <kbd>Message</kbd> entity. #14 Call the <kbd>getResultList()</kbd> method of the query object to get the results. The query that is created and executed will be <kbd>SELECT * FROM MESSAGE</kbd>. #15 Commit the transaction. #16 Check the size of the list of messages retrieved from the database. #17 Check that the message we persisted is in the database. We use the JUnit 5 <kbd>assertAll</kbd> method, which always checks all the assertions that are passed to it, even if some of them fail. The two assertions that we verify are conceptually related.
The native Hibernate test shows how `Configuration`, a service registry, and an annotated class produce a `SessionFactory` for storing a message. section 2.4
The persistence context governs when changes reach the database. On loading an entity, Hibernate retains a snapshot; it compares the managed instance with that snapshot to detect changes. It normally flushes changes at transaction commit and may flush before a query. `FlushModeType.COMMIT` postpones that query-time synchronization, so query results may differ from the changed object in memory. section 10.2.3 section 10.2.9
Mappings affect both generated SQL and its cost:
- An immutable entity can avoid updates and dirty checking; `@org.hibernate.annotations.Immutable` marks one. section 5.3.3
- Built-in Java-to-SQL type mappings cover standard types and additional Hibernate adapters; a configured SQL dialect translates types for vendor-specific schema generation. section 6.3.1
- An `@OrderColumn` preserves list positions, but removing an early element can require an update for every following element. section 8.1.6
Inspect the SQL Hibernate issues rather than treating ORM as a substitute for SQL knowledge. Compare JPA, native Hibernate, and Spring Data JPA for portability, dependencies, code volume, and execution speed; Spring can also manage a Hibernate `SessionFactory` and transactions in a DAO-based application. section 1.3 section 2.8 section 14.6
