JPA 

Introduction

The tutorial, JPA CRUD, will show you how to use JPA(Java Persistence API) for selecting, inserting, updating and deleting data into/from database. The acronym CRUD means Create, Read, Update and Delete.

What is JPA?

The Java Persistence API (JPA) is a Java specification for accessing, persisting, and managing data between Java objects / classes and a relational database.

Pros of JPA

  • The JPA is used to reduce the burden of writing codes for relational object management, a programmer or developer follows the ‘JPA Provider’ framework, which allows easy interaction with database instance.
  • The JPA being a Java framework a programmer also needs not to worry about the SQL part of the code, he/she may need to hardly concentrate on SQL coding.
  • In EJB 3.0 the persistence layer was separated and defined as a replacement of EJB 2 CMP Entity Beans specification.
  • Being JPA an open source API, various enterprise vendors such as Oracle, Redhat, Eclipse, etc. provide new products by adding the JPA persistence flavor in them. Some of these products include Hibernate, Eclipselink, Toplink, Spring Data JPA.
  • JPA allows you to avoid writing DDL in a database specific dialect of SQL. Instead you write mappings in XML, or using Java annotations.
  • JPA allows you to avoid writing DML in the database specific dialect of SQL.
  • JPA allows you to load and save Java objects and graphs without any DML language at all.
  • When you do need to perform queries, JPQL allows you to express the queries in terms of the Java entities rather than the (native) SQL tables and columns.

Cons of JPA

  • If performance is an overriding concern, JPA does tend to get in the way by adding layers between your application and the database. If your application requires you to extensively hand-optimize the native database queries and schemas to maximize performance, JPA is probably not a good fit.
  • JPA is probably also not fit for you, if you are much more comfortable juggling Java, JDBC and SQL in the same application, than with letting the ORM deal with the messy details.

The following example shows you how to use JPA to write a CRUD application.

Prerequisites

Eclipse 4.12, Java 8 or 12, Hibernate 5.4.6, MySQL 8.0.17, Maven 3.6.1 or Gradle 5.6

Creating Project

For this tutorial we will create a standalone maven project in Eclipse.

You can create a maven or gradle project in Eclipse. The name of the project is jpa-crud.

Updating Build File

You can use either gradle or maven build file to add dependencies as shown below.

We are using JPA but we must have to provide the provider of the JPA specification and here we are using Hibernate.

Gradle File – build.gradle

apply plugin: 'java'

sourceCompatibility = 12
targetCompatibility = 12

repositories {
    mavenLocal()
    mavenCentral()
}

dependencies {
	implementation("org.hibernate:hibernate-entitymanager:5.4.6.Final")
	runtime('mysql:mysql-connector-java:8.0.17')
}

Maven – pom.xml

Arctype: maven-arctype-quickstart
Group Id : com.roytuts
Artifact Id : jpa-crud
<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-crud</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>
	
	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<java.version>12</java.version>
		<hibernate.version>5.4.6.Final</hibernate.version>
		<mysqlconnector.version>8.0.17</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>

Creating META-INF Folder

Create META-INF folder under src/main/resources directory. This folder is used to put persistence configuration file.

Creating Persistence Configuration File

Create an XML file persistence.xml under src/main/resources/META-INF.

Do right-click on META-INF in the project and go New -> file. Give File name: as persistence.xml and click on Finish button.

<?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.entity.UserDetails</class>
		<properties>
			<property name="javax.persistence.jdbc.driver"
				value="com.mysql.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, we have transaction-type as RESOURCE_LOCAL.

There are two types of Transaction management types supported in JPA:

  • RESOURCE LOCAL
  • JTA or GLOBAL

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 need to 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.

Creating Entity Class

Create below entity class UserDetails that will map Java attributes to corresponding database table columns.

package com.roytuts.jpa.crud.entity;

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_details")
public class UserDetails {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "id")
	private int id;

	@Column(name = "first_name")
	private String firstName;

	@Column(name = "last_name")
	private String lastName;

	@Column(name = "email")
	private String email;

	@Column(name = "dob")
	private String dob;

	public UserDetails() {
	}

	public UserDetails(int id, String firstName, String lastName, String email, String dob) {
		this.id = id;
		this.firstName = firstName;
		this.lastName = lastName;
		this.email = email;
		this.dob = dob;
	}

	//getters and setters

	@Override
	public String toString() {
		return "UserDetails [id=" + id + ", firstName=" + firstName + ", lastName=" + lastName + ", email=" + email
				+ ", dob=" + dob + "]";
	}

}

Creating Custom Exception

Create below custom exception class JpaException that will wrap and throw exceptions.

package com.roytuts.jpa.crud.exception;

public class JpaException extends RuntimeException {

	private static final long serialVersionUID = 1L;

	public JpaException(String msg) {
		super(msg);
	}

	public JpaException(Throwable t) {
		super(t);
	}

	public JpaException(String msg, Throwable t) {
		super(msg, t);
	}

}

Getting EntityManager

Now create an enum PersistenceManager for creating EntityManagerFactory and EntityManager.

Enum is the best for creating singleton instance and as we need single instance for persistence manager, so we are using singleton pattern.

package com.roytuts.jpa.crud.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();
	}

}

CRUD Operations

Now create a class UserDetailsCrud for database operation.

package com.roytuts.jpa.crud;

import java.util.List;

import javax.persistence.EntityManager;

import com.roytuts.jpa.crud.entity.UserDetails;
import com.roytuts.jpa.crud.exception.JpaException;

public class UserDeatilsCrud {

	private EntityManager em;

	public UserDeatilsCrud(EntityManager em) {
		this.em = em;
	}

	public UserDetails getUserDetails(int id) {
		try {
			UserDetails userDetails = em.find(UserDetails.class, id);
			return userDetails;
		} catch (JpaException ex) {
			throw new JpaException(ex.getMessage(), ex);
		}
	}

	public List<UserDetails> getUsersDetails() {
		try {
			String sql = "select u from UserDetails u";
			List<UserDetails> userDetails = em.createQuery(sql, UserDetails.class).getResultList();
			return userDetails;
		} catch (JpaException ex) {
			throw new JpaException(ex.getMessage(), ex);
		}
	}

	public void addUserDetails(UserDetails userDetails) {
		try {
			if (!em.getTransaction().isActive()) {
				em.getTransaction().begin();
			}
			em.persist(userDetails);
			em.getTransaction().commit();
		} catch (JpaException e) {
			em.getTransaction().rollback();
			throw new JpaException(e.getMessage(), e);
		}
	}

	public void updateUserDetails(UserDetails userDetails) {
		try {
			if (!em.getTransaction().isActive()) {
				em.getTransaction().begin();
			}
			UserDetails details = getUserDetails(userDetails.getId());
			details.setFirstName(userDetails.getFirstName());
			details.setLastName(userDetails.getLastName());
			details.setEmail(userDetails.getEmail());
			details.setDob(userDetails.getDob());
			em.getTransaction().commit();
		} catch (JpaException e) {
			em.getTransaction().rollback();
			throw new JpaException(e.getMessage(), e);
		}
	}

	public void deleteUserDetails(int id) {
		try {
			if (!em.getTransaction().isActive()) {
				em.getTransaction().begin();
			}
			UserDetails details = getUserDetails(id);
			em.remove(details);
			em.getTransaction().commit();
		} catch (JpaException e) {
			em.getTransaction().rollback();
			throw new JpaException(e.getMessage(), e);
		}
	}

}

Creating Main Class

Create a main class which will run and test CRUD application.

package com.roytuts.jpa.crud.app;

import java.util.List;

import javax.persistence.EntityManager;

import com.roytuts.jpa.crud.UserDeatilsCrud;
import com.roytuts.jpa.crud.entity.UserDetails;
import com.roytuts.jpa.crud.manager.PersistenceManager;

public class JpaCrudApp {

	public static void main(String[] args) {
		EntityManager em = PersistenceManager._INSTANCE.getEntityManager();

		UserDeatilsCrud userDeatilsCrud = new UserDeatilsCrud(em);

		// user details for user id 7
		try {
			UserDetails userDetails = userDeatilsCrud.getUserDetails(7);
			System.out.println(userDetails);
		} catch (Exception e) {
			e.printStackTrace();
		}

		// get all user details
		try {
			List<UserDetails> detailsList = userDeatilsCrud.getUsersDetails();
			for (UserDetails details : detailsList) {
				System.out.println(details);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		// add new user
		try {
			UserDetails user = new UserDetails();
			user.setFirstName("Liton");
			user.setLastName("Sarkar");
			user.setEmail("[email protected]");
			user.setDob("20-07-1990");
			userDeatilsCrud.addUserDetails(user);
		} catch (Exception e) {
			e.printStackTrace();
		}

		// get all users after addition
		try {
			List<UserDetails> detailsList = userDeatilsCrud.getUsersDetails();
			for (UserDetails details : detailsList) {
				System.out.println(details);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		// update user for id 10
		try {
			UserDetails user = new UserDetails();
			user.setId(10);
			user.setFirstName("Liton");
			user.setLastName("Sarkar");
			user.setEmail("[email protected]");
			user.setDob("14-07-1990");
			userDeatilsCrud.updateUserDetails(user);
		} catch (Exception e) {
			e.printStackTrace();
		}

		// get all users after update
		try {
			List<UserDetails> detailsList = userDeatilsCrud.getUsersDetails();
			for (UserDetails details : detailsList) {
				System.out.println(details);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		// delete user for id 9
		try {
			userDeatilsCrud.deleteUserDetails(9);
		} catch (Exception e) {
			e.printStackTrace();
		}

		// get all users after deletion
		try {
			List<UserDetails> detailsList = userDeatilsCrud.getUsersDetails();
			for (UserDetails details : detailsList) {
				System.out.println(details);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		// close EntityManager
		em.close();

		// close EntityManagerFactory
		PersistenceManager._INSTANCE.close();
	}

}

Creating MySQL Table

Create table user_details in MySQL server under roytuts database and dump some data into it.

Table Structure

CREATE TABLE `user_details` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `first_name` varchar(20) NOT NULL,
  `last_name` varchar(15) NOT NULL,
  `email` varchar(100) NOT NULL,
  `dob` varchar(16) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

Sample Data

insert  into
`user_details`(`id`,`first_name`,`last_name`,`email`,`dob`)
values
(7,'Soumitra','Roy','[email protected]','30-08-2016'),
(8,'Souvik','Sanyal','[email protected]','30-09-1991'),
(9,'Abc','Xyz','[email protected]','12-01-1998');

Testing the Application

Run the above main class, you will see below output in the console.

Hibernate: 
    select
        userdetail0_.id as id1_0_0_,
        userdetail0_.dob as dob2_0_0_,
        userdetail0_.email as email3_0_0_,
        userdetail0_.first_name as first_na4_0_0_,
        userdetail0_.last_name as last_nam5_0_0_ 
    from
        user_details userdetail0_ 
    where
        userdetail0_.id=?
UserDetails [id=7, firstName=Soumitra, lastName=Roy, [email protected], dob=30-08-2016]
Hibernate: 
    select
        userdetail0_.id as id1_0_,
        userdetail0_.dob as dob2_0_,
        userdetail0_.email as email3_0_,
        userdetail0_.first_name as first_na4_0_,
        userdetail0_.last_name as last_nam5_0_ 
    from
        user_details userdetail0_
UserDetails [id=7, firstName=Soumitra, lastName=Roy, [email protected], dob=30-08-2016]
UserDetails [id=8, firstName=Souvik, lastName=Sanyal, [email protected], dob=30-09-1991]
UserDetails [id=9, firstName=Abc, lastName=Xyz, [email protected], dob=12-01-1998]
Hibernate: 
    insert 
    into
        user_details
        (dob, email, first_name, last_name) 
    values
        (?, ?, ?, ?)
Hibernate: 
    select
        userdetail0_.id as id1_0_,
        userdetail0_.dob as dob2_0_,
        userdetail0_.email as email3_0_,
        userdetail0_.first_name as first_na4_0_,
        userdetail0_.last_name as last_nam5_0_ 
    from
        user_details userdetail0_
UserDetails [id=7, firstName=Soumitra, lastName=Roy, [email protected], dob=30-08-2016]
UserDetails [id=8, firstName=Souvik, lastName=Sanyal, [email protected], dob=30-09-1991]
UserDetails [id=9, firstName=Abc, lastName=Xyz, [email protected], dob=12-01-1998]
UserDetails [id=10, firstName=Liton, lastName=Sarkar, [email protected], dob=20-07-1990]
Hibernate: 
    select
        userdetail0_.id as id1_0_,
        userdetail0_.dob as dob2_0_,
        userdetail0_.email as email3_0_,
        userdetail0_.first_name as first_na4_0_,
        userdetail0_.last_name as last_nam5_0_ 
    from
        user_details userdetail0_
UserDetails [id=7, firstName=Soumitra, lastName=Roy, [email protected], dob=30-08-2016]
UserDetails [id=8, firstName=Souvik, lastName=Sanyal, [email protected], dob=30-09-1991]
UserDetails [id=9, firstName=Abc, lastName=Xyz, [email protected], dob=12-01-1998]
UserDetails [id=10, firstName=Liton, lastName=Sarkar, [email protected], dob=14-07-1990]
Hibernate: 
    select
        userdetail0_.id as id1_0_,
        userdetail0_.dob as dob2_0_,
        userdetail0_.email as email3_0_,
        userdetail0_.first_name as first_na4_0_,
        userdetail0_.last_name as last_nam5_0_ 
    from
        user_details userdetail0_
UserDetails [id=7, firstName=Soumitra, lastName=Roy, [email protected], dob=30-08-2016]
UserDetails [id=8, firstName=Souvik, lastName=Sanyal, [email protected], dob=30-09-1991]
UserDetails [id=9, firstName=Abc, lastName=Xyz, [email protected], dob=12-01-1998]
UserDetails [id=10, firstName=Liton, lastName=Sarkar, [email protected], dob=14-07-1990]

Source Code

Download Source Code

Thanks for reading.

Tags:

Leave a Reply

Your email address will not be published. Required fields are marked *