Introduction
This tutorial will show you how to use JPA(Java Persistence API) Criteria API Queries for selecting data from database. The Java Persistence API (JPA) is a Java specification for accessing, persisting, and managing data between Java objects / classes and a relational database.
The Criteria API is used to define queries for entities and their persistent state by creating query-defining objects. Criteria API queries are written using Java programming language APIs, are typesafe, and are portable. Such queries work regardless of the underlying data store.
The major advantage of Criteria API is that errors can be detected earlier during the compile time. String-based JPQL(Java Persistence Query Language) queries and JPA criteria based queries are same in performance and efficiency.
Related Posts:
Steps to create Criteria Query
EntityManager
instance is used to create aCriteriaBuilder
object.CriteriaQuery
instance is used to create a query object fromCriteriaBuilder
object. The attributes of this object will be modified with the details of the query.CriteriaQuery.form()
method is called to set the Root of the query.CriteriaQuery.select()
is called to set the result list type for a particular POJO class mapped to a database table.TypedQuery<T>
instance is used to prepare a query for execution and specifying the type of the query result.getResultList()
method is used on theTypedQuery<T>
object for executing a query to return the result list of a collection of entities.
The following example shows you how to use JPA Criteria Queries in Java based application.
Prerequisites
Java at least 8, Gradle 6.5.1, Maven 3.6.3, Hibernate Entity Manager 5.4.21, MySQL Connector 8.0.21, JAXB API 2.4.0 (if JDK > 8)
Project Setup
You can create gradle or maven based Java project in your favorite IDE or tool.
Use below build.gradle script if you are using gradle based project:
plugins {
id 'java-library'
}
sourceCompatibility = 12
targetCompatibility = 12
repositories {
jcenter()
}
dependencies {
implementation 'org.hibernate:hibernate-entitymanager:5.4.21.Final'
implementation 'mysql:mysql-connector-java:8.0.21'
}
Use below pom.xml file if you create maven based project:
<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.roytuts</groupId>
<artifactId>jpa-criteria-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>at least 1.8</java.version>
<hibernate.version>5.4.21.Final</hibernate.version>
<mysqlconnector.version>8.0.21</mysqlconnector.version>
</properties>
<dependencies>
<!-- JPA -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.version}</version>
</dependency>
<!-- mysql java connector -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysqlconnector.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
Persistence Unit
Create an XML file persistence.xml under src/main/resources/META-INF folder.
In the following file I have added MySQL database configurations, any table/class mapping Java file, persistence unit name, any other extra configuration.
<?xml version="1.0" encoding="UTF-8"?>
<persistence 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_2.xsd"
version="2.2">
<persistence-unit name="userPersistanceUnit"
transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<class>com.roytuts.jpa.criteria.api.entity.User</class>
<properties>
<property name="javax.persistence.jdbc.driver"
value="com.mysql.cj.jdbc.Driver" />
<property name="javax.persistence.jdbc.url"
value="jdbc:mysql://localhost:3306/roytuts" />
<property name="javax.persistence.jdbc.user" value="root" />
<property name="javax.persistence.jdbc.password"
value="root" />
<property name="dialect"
value="org.hibernate.dialect.MySQLDialect" />
<property
name="hibernate.transaction.flush_before_completion" value="true" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="true" />
</properties>
</persistence-unit>
</persistence>
In the above XML file, I have declared transaction-type as RESOURCE_LOCAL. There are two types of Transaction management types supported in JPA.
- RESOURCE LOCAL Transactions
- JTA or GLOBAL Transactions
Resource local transactions refer to the native transactions of the JDBC Driver whereas JTA transactions refer to the transactions of the JEE server. A Resource Local transaction involves a single transactional resource, for example a JDBC Connection. Whenever you need two or more resources (for example, a JMS Connection and a JDBC Connection) within a single transaction, you use JTA Transaction.
Container Managed Entity Managers always use JTA transactions as the container takes care of transaction life cycle management and spawning the transaction across multiple transactional resources. Application Managed Entity Managers can use either Resource Local Transactions or JTA transactions.
Normally in JTA or global transaction, a third party transaction monitor enlists the different transactional resources within a transaction, prepares them for a commit and finally commits the transaction. This process of first preparing the resources for transaction(by doing a dry run) and then committing(or rolling back) is called a 2 phase commit.
Entity Class
Create below entity class User under src/main/java folder. This class maps the fields or attributes to the table columns.
package com.roytuts.jpa.criteria.api.entity;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "user")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private int id;
@Column(name = "name")
private String name;
@Column(name = "phone")
private String phone;
@Column(name = "email")
private String email;
@Column(name = "address")
private String address;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + ", phone=" + phone + ", email=" + email + ", address=" + address
+ "]";
}
}
Persistence Manager
Now create an enum PersistenceManager for creating EntityManagerFactory and EntityManager.
I am using enum to create singleton instance for this Persistence Manager.
package com.roytuts.jpa.criteria.api.persistence.manager;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
public enum PersistenceManager {
_INSTANCE;
private EntityManagerFactory emf;
private PersistenceManager() {
emf = Persistence.createEntityManagerFactory("userPersistanceUnit");
}
public EntityManager getEntityManager() {
return emf.createEntityManager();
}
public void close() {
emf.close();
}
}
Main Class
Create a class with main method to test the application.
package com.roytuts.jpa.criteria.api.app;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import com.roytuts.jpa.criteria.api.entity.User;
import com.roytuts.jpa.criteria.api.persistence.manager.PersistenceManager;
public class JpaCriteriaApp {
public static void main(String[] args) {
EntityManager em = PersistenceManager._INSTANCE.getEntityManager();
// create user for id 35
try {
em.getTransaction().begin();
User u = new User();
u.setName("Liton");
u.setEmail("liton.sarkar@email.com");
u.setPhone("1407874760");
u.setAddress("Mars");
em.persist(u);
em.getTransaction().commit();
System.out.println("User " + u + " successfully saved");
} catch (Exception e) {
em.getTransaction().rollback();
e.printStackTrace();
}
CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery<Object> criteriaQuery = criteriaBuilder.createQuery();
Root<User> from = criteriaQuery.from(User.class);
// select all records
System.out.println("Select all records");
System.out.println("------------------");
System.out.println();
CriteriaQuery<Object> select = criteriaQuery.select(from);
TypedQuery<Object> typedQuery = em.createQuery(select);
List<Object> resultlist = typedQuery.getResultList();
for (Object o : resultlist) {
User u = (User) o;
System.out.println(u);
}
// Ordering the records
System.out.println();
System.out.println("Select all records in ascending order");
System.out.println("-------------------------------------");
System.out.println();
CriteriaQuery<Object> select1 = criteriaQuery.select(from);
select1.orderBy(criteriaBuilder.asc(from.get("name")));
TypedQuery<Object> typedQuery1 = em.createQuery(select);
List<Object> resultlist1 = typedQuery1.getResultList();
for (Object o : resultlist1) {
User u = (User) o;
System.out.println(u);
}
// update user for id 35
try {
User user = em.find(User.class, 35);
user.setName("Liton Sarkar");
user.setEmail("liton.sarkar@email.com");
user.setPhone("140787476990");
user.setAddress("Earth");
em.persist(user);
em.getTransaction().commit();
System.out.println("User " + user + " successfully updated");
} catch (Exception e) {
e.printStackTrace();
} finally {
em.close();
PersistenceManager._INSTANCE.close();
}
}
}
MySQL Table
Create table user under roytuts database in MySQL server and dump some data into it.
CREATE DATABASE IF NOT EXISTS `roytuts`;
USE `roytuts`;
CREATE TABLE IF NOT EXISTS `user` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL,
`email` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL,
`phone` int unsigned NOT NULL,
`address` varchar(250) COLLATE utf8mb4_unicode_ci NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=34 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO `user` (`id`, `name`, `email`, `phone`, `address`) VALUES
(1, 'Soumitra', 'soumitra@roytuts.com', 43256789, 'Earth'),
(2, 'Rahul', 'rahul@roytuts.com', 65465363, 'Mars');
Testing the Application
Run the above main class, you will see below output in the console.
Hibernate:
insert
into
user
(address, email, name, phone)
values
(?, ?, ?, ?)
User User [id=35, name=Liton, phone=1407874760, email=liton.sarkar@email.com, address=Mars] successfully saved
Select all records
------------------
Hibernate:
select
user0_.id as id1_0_,
user0_.address as address2_0_,
user0_.email as email3_0_,
user0_.name as name4_0_,
user0_.phone as phone5_0_
from
user user0_
User [id=1, name=Soumitra, phone=43256789, email=soumitra@roytuts.com, address=Earth]
User [id=2, name=Rahul, phone=65465363, email=rahul@roytuts.com, address=Mars]
User [id=35, name=Liton, phone=1407874760, email=liton.sarkar@email.com, address=Mars]
Select all records in ascending order
-------------------------------------
Hibernate:
select
user0_.id as id1_0_,
user0_.address as address2_0_,
user0_.email as email3_0_,
user0_.name as name4_0_,
user0_.phone as phone5_0_
from
user user0_
order by
user0_.name asc
User [id=35, name=Liton, phone=1407874760, email=liton.sarkar@email.com, address=Mars]
User [id=2, name=Rahul, phone=65465363, email=rahul@roytuts.com, address=Mars]
User [id=1, name=Soumitra, phone=43256789, email=soumitra@roytuts.com, address=Earth]
Source Code
Thanks for reading.