Hibernate/JPA Named Query XML and Annotation Example

This tutorial show how to use Hibernate/JPA Named Queries. We start by explaining why we would use named queries. Next, we show an example of how to use named queries, either with annotations or XML configuration.

Why Use Named Queries?

Advantages

  • Named Queries are compiled when the SessionFactory is instantiated. Therefore, all your named queries are validated upon application startup time. Errors are detected quickly.
  • Named Queries provide significant performance benefit. All named queries are compiled at startup. This means repeatable executions uses the same compiled queries.

Disadvantages

  • Not customizable at runtime. Therefore, not suitable for highly dynamic queries.
  • Named Queries are static. You won’t be able to change these queries within a running application server, without reloading the SessionFactory

Maven Dependencies

We use Apache Maven to manage the projects dependencies.

<?xml version="1.0" encoding="UTF-8"?>
<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>
    <groupId>com.memorynotfound.db.hibernate</groupId>
    <artifactId>jpa-named-query</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>war</packaging>
    <name>HIBERNATE - ${project.artifactId}</name>
    <url>http://memorynotfound.com</url>

    <properties>
        <mysql.driver.version>6.0.4</mysql.driver.version>
        <hibernate.version>5.2.3.Final</hibernate.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.driver.version}</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>${hibernate.version}</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.5.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

Create Model + Mappings

You can annotate the class with the @NamedQueries annotation to register multiple @NamedQuery annotations. This annotation specifies a static named query. These queries can be re-used without having the overhead to re-compile the same query again. Query names are scoped to the persistence unit. The Named Query can be applied to an entity or mapped superclass.

package com.memorynotfound.hibernate;

import javax.persistence.*;

@Entity
@NamedQueries(value = {
        @NamedQuery(
                name = "Book.findAll",
                query = "SELECT b FROM Book b"),
        @NamedQuery(
                name = "Book.findById",
                query = "SELECT b FROM Book b WHERE b.id = :id")
})
public class Book {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String title;

    public Book() {
    }

    public Book(String title) {
        this.title = title;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    @Override
    public String toString() {
        return "Book{" +
                "id=" + id +
                ", title='" + title + '\'' +
                '}';
    }
}

If you prefer XML over Annotations, you can use the equivalent JPA XML mapping. This file is located in the src/main/resources/META-INF folder and is named orm.xml.

<?xml version="1.0" encoding="UTF-8" ?>
<entity-mappings xmlns="http://xmlns.jcp.org/xml/ns/persistence/orm"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence/orm
                                     http://xmlns.jcp.org/xml/ns/persistence/orm_2_0.xsd" version="2.1">

    <!-- JPA Named Queries -->
    <named-query name="Book.findAll">
        <query>SELECT b FROM Book b</query>
    </named-query>
    <named-query name="Book.findById">
        <query>SELECT b FROM Book b WHERE b.id = :id</query>
    </named-query>

    <!-- entity mapping -->
    <entity class="com.memorynotfound.hibernate.Book">
        <attributes>
            <basic name="title"/>
        </attributes>
    </entity>

</entity-mappings>

Hibernate/JPA Configuration

We configure the JPA Persistence Unit using the persistence.xml file, which is located in the src/main/resources/META-INF directory.

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
                                 http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
    <persistence-unit name="mnf-pu" transaction-type="RESOURCE_LOCAL">
        <!-- enable if you want xml mappings
        <mapping-file>META-INF/orm.xml</mapping-file>
        -->
        <properties>
            <!-- Configuring JDBC properties -->
            <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/memorynotfound?serverTimezone=Europe/Brussels"/>
            <property name="javax.persistence.jdbc.user" value="root"/>
            <property name="javax.persistence.jdbc.password" value=""/>
            <property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>

            <!-- Hibernate properties -->
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
            <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
            <property name="hibernate.format_sql" value="false"/>
            <property name="hibernate.show_sql" value="true"/>
        </properties>
    </persistence-unit>
</persistence>

Create, Run and Test

package com.memorynotfound.hibernate;

import javax.persistence.*;
import java.util.List;

public class App {

    public static void main (String...args) throws InterruptedException {

        EntityManagerFactory emf = Persistence.createEntityManagerFactory("mnf-pu");
        EntityManager em = emf.createEntityManager();

        em.getTransaction().begin();
        Book book = new Book("Hibernate/JPA Named Query Example");
        em.persist(book);
        em.getTransaction().commit();

        List<Book> r1 = em.createNamedQuery("Book.findAll", Book.class).getResultList();
        System.out.println(r1);

        Book r2 = em.createNamedQuery("Book.findById", Book.class)
                .setParameter("id", 1)
                .getSingleResult();
        System.out.println(r2);

        emf.close();
    }
}
...
Hibernate: insert into Book (title) values (?)
Hibernate: select book0_.id as id1_0_, book0_.title as title2_0_ from Book book0_
[Book{id=1, title='Hibernate/JPA Named Query Example'}]
Hibernate: select book0_.id as id1_0_, book0_.title as title2_0_ from Book book0_ where book0_.id=?
Book{id=1, title='Hibernate/JPA Named Query Example'}
Hibernate: SELECT * FROM Book
[Book{id=1, title='Hibernate/JPA Named Query Example'}]
Hibernate: SELECT * FROM Book WHERE id = ?
Book{id=1, title='Hibernate/JPA Named Query Example'}
...

References

Download

You may also like...