BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage News Hibernate ORM 6.0 Delivers Improved Performance

Hibernate ORM 6.0 Delivers Improved Performance

This item in japanese

Lire ce contenu en français

Six-and-a-half years after the release of Hibernate ORM 5.0, Red Hat has released version 6.0 of their flagship product, Hibernate ORM, the popular object-relational mapping persistence utility. Significant new features include a migration to the Jakarta Persistence 3.0 specification, performance improvements to JDBC, and HQL translation and criteria translation. With this release, Hibernate requires a minimum of Java 11.

With Hibernate 6.0, Java persistence is no longer defined by the Java Persistence API under Java EE, but rather it moves to the Jakarta Persistence 3.0 specification under Jakarta EE. This means the javax.persistence package is no longer available. Developers must now import the jakarta.persistence package in their Java code. An example entity would look as follows:

    
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 java.util.Date;
import org.hibernate.annotations.GenericGenerator;

@Entity
@Table(name = "EVENTS")
public class Event {

    @Id
    @GeneratedValue(generator = "increment")
    @GenericGenerator(name = "increment", strategy = "increment")
    private Long id;

    private String title;

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "EVENT_DATE")
    private Date date;

    public Event() {
        // this form used by Hibernate
    }

    // getter methods
    // setter methods
}
    

The Java JDBC API provides ResultSet, an interface to represent the database result usually generated by executing a statement that queries the database. There are two ways to extract data, read-by-name and read-by-position, from a result set. With this release, reading from an instance of a ResultSet changes from read-by-name to read-by-position. Regarding this, Red Hat's lead software engineer and Hibernate ORM's lead developer Steve Ebersole mentioned in the release notes that:

A few years ago, around the 5.4 timeframe, we worked with the amazing performance team at Red Hat to squeeze even more great performance out of Hibernate ORM. This work was part of a larger effort to improve the performance of WildFly.

Ultimately, the limiting factor to additional improvements within Hibernate was our approach of reading values from a JDBC ResultSet by name rather than by position. For every JDBC driver out there, reading by name is slower.

In other words, this suggests that read-by-position is faster compared to read-by-name as explained by Firebird JDBC driver maintainer Mark Rotteveel in this StackOverflow post:

Row values will usually be stored in an array or list because that most naturally matches the way the data is received from the database server. As a result, retrieving values by index will be the simplest.

On the other hand, looking up by column name is more work. Column names need to be treated case-insensitive, which has an additional cost whether you normalize using lower or uppercase, or use a case-insensitive lookup using a TreeMap.

Changes to read-by-position in ResultSet also led to the changes in the Hibernate Type System. It removes all the string-based approaches for specifying types, including the @AnyMetaDef, @AnyMetaDefs, @TypeDef and @TypeDefs deprecated annotations. Hibernate 6.0 also redesigns its annotations claiming better type safety. Developers looking to see the changes can refer to the user guide for the domain model mapping details.

On top of that, as a side effect of read-by-position in Hibernate 6.0, the generated SQL select queries are longer required to create named column aliases, resulting in much more readable generated SQL.

Pre-Hibernate 6.0 Hibernate 6.0
select event0_.id as id1_0_,
event0_.event_date as event_da2_0_,
event0_.title as title3_0_
from events event0_
select e1_0.id,e1_0.event_date,e1_0.title
from events e1_0

Hibernate uses HQL, a query language similar to SQL, except HQL is object-oriented and understands notions such as inheritance, polymorphism and association.

HQL is written using ANTLR, a powerful parser generator for reading, processing, executing, or translating structured text or binary files. This version upgrades from ANTLR 2 to ANTLR 4, which in turn makes HQL more efficient, as stated in the release notes.

Another significant change in Hibernate 6.0 is the Semantic Query Model (SQM), a new query parser to address both HQL and criteria queries, claiming to provide better performance than the previous Hibernate HQL query capabilities.

This release removes Hibernate's legacy Criteria API, and support for criteria queries is now offered solely through the Jakarta Persistence API. A new @Incubating annotation was also introduced, intending to warn users that a particular contract may change in the future.

This release offers many other new features and internal changes. The Maven artifacts are already published in Maven Central, so Hibernate 6.0 is ready for inclusion in any Java application. Developers interested in migrating to Hibernate 6.0 can read the migration guide. New Hibernate developers can leverage the Hibernate Getting Started Guide, covering most user-facing concepts and APIs.

About the Author

Rate this Article

Adoption
Style

BT